<commit_before>use std::sync::mpsc::Sender;
use std::cell::RefCell;

use sys::win32::ffi;

use event::Event;

thread_local!(
   pub static SENDER: RefCell<Option<Sender<Event>>> = RefCell::new(None)
);

fn send(event: Event) {
   SENDER.with(|sender_cell| {
      let sender_option = sender_cell.borrow();
      let sender = match *sender_option {
         Some(ref sender) => sender,
         None => return
      };

      sender.send(event).ok();
   });
}

#[allow(unused_variables)]
pub unsafe extern "system" fn wnd_proc(
   hwnd: ffi::HWND,
   msg: ffi::c_uint,
   wparam: ffi::WPARAM,
   lparam: ffi::LPARAM
) -> ffi::LRESULT {
   match msg {
      ffi::WM_CLOSE => {
         ffi::PostQuitMessage(0);
         send(Event::Quit);
         0
      },
      ffi::WM_ERASEBKGND => {
         1
      },
      ffi::WM_SIZE => {
         let width = ffi::LOWORD(lparam as ffi::DWORD) as u32;
         let height = ffi::HIWORD(lparam as ffi::DWORD) as u32;
         send(Event::Resize(width, height));
         0
      },
      ffi::WM_CREATE => {
         0
      },
      _ => {
         ffi::DefWindowProcW(hwnd, msg, wparam, lparam)
      }
   }
}
<commit_msg>Reordering event handling on Windows wnd proc<commit_after>use std::sync::mpsc::Sender;
use std::cell::RefCell;

use sys::win32::ffi;

use event::Event;

thread_local!(
   pub static SENDER: RefCell<Option<Sender<Event>>> = RefCell::new(None)
);

fn send(event: Event) {
   SENDER.with(|sender_cell| {
      let sender_option = sender_cell.borrow();
      let sender = match *sender_option {
         Some(ref sender) => sender,
         None => return
      };

      sender.send(event).ok();
   });
}

#[allow(unused_variables)]
pub unsafe extern "system" fn wnd_proc(
   hwnd: ffi::HWND,
   msg: ffi::c_uint,
   wparam: ffi::WPARAM,
   lparam: ffi::LPARAM
) -> ffi::LRESULT {
   match msg {
      ffi::WM_CREATE => {
         0
      },

      ffi::WM_ERASEBKGND => {
         1
      },

      ffi::WM_SIZE => {
         let width = ffi::LOWORD(lparam as ffi::DWORD) as u32;
         let height = ffi::HIWORD(lparam as ffi::DWORD) as u32;
         send(Event::Resize(width, height));
         0
      },

      ffi::WM_CLOSE => {
         ffi::PostQuitMessage(0);
         send(Event::Quit);
         0
      },

      _ => {
         ffi::DefWindowProcW(hwnd, msg, wparam, lparam)
      }
   }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context};
use crate_universe_resolver::{config::Config, renderer::Renderer};
use indoc::indoc;
use log::*;
use structopt::StructOpt;

// Options which don't affect the contents of the generated should be on this struct.
// These fields are not factored into cache keys.
//
// Anything which affects the contents of the generated output should live on `config::Config`.
#[derive(StructOpt)]
struct Opt {
    #[structopt(long)]
    repo_name: String,
    #[structopt(long = "input_path", parse(from_os_str))]
    input_path: PathBuf,
    #[structopt(long = "repository_dir", parse(from_os_str))]
    repository_dir: PathBuf,
    #[structopt(long = "lockfile", parse(from_os_str))]
    lockfile: Option<PathBuf>,
    #[structopt(long = "update-lockfile")]
    update_lockfile: bool,
}

fn main() -> anyhow::Result<()> {
    env_logger::init();

    let opt = Opt::from_args();
    trace!("Parsing config from {:?}", opt.input_path);

    let config: Config = {
        let config_file = std::fs::File::open(&opt.input_path)
            .with_context(|| format!("Failed to open config file at {:?}", opt.input_path))?;
        serde_json::from_reader(config_file)
            .with_context(|| format!("Failed to parse config file {:?}", opt.input_path))?
    };

    let lockfile = &opt.lockfile;
    if opt.update_lockfile {
        if lockfile.is_none() {
            eprintln!("Not updating lockfile for `crate_universe` repository with name \"{}\" because it has no `lockfile` attribute.", opt.repo_name);
        }
    } else if let Some(lockfile) = lockfile {
        return reuse_lockfile(config, &lockfile, &opt);
    }

    generate_dependencies(config, &opt)
}

fn reuse_lockfile(config: Config, lockfile: &Path, opt: &Opt) -> anyhow::Result<()> {
    trace!("Preprocessing config");
    let mut resolver = config.preprocess()?;

    let renderer = Renderer::new_from_lockfile(lockfile)?;

    // TODO: Add lockfile versioning and check that here

    if !renderer.matches_digest(&resolver.digest()?) {
        return Err(anyhow!(indoc! { r#"
            "rules_rust_external: Lockfile at {} is out of date, please either:
            1. Re-run bazel with the environment variable `RULES_RUST_REPIN=true`, to update the lockfile
            2. Remove the `lockfile` attribute from the `crate_universe` repository rule with name \"{}\" to use floating dependency versions", lockfile.display(), opt.repo_name
        "# }));
    }

    renderer.render(&opt.repository_dir)
}

fn generate_dependencies(config: Config, opt: &Opt) -> anyhow::Result<()> {
    trace!("Preprocessing config");
    let resolver = config.preprocess()?;

    // This will contain the mapping of the workspace member (i.e. toplevel) packages' direct
    // dependencies package names to their package Bazel repository name (e.g. `bzip2 ->
    // bzip2__0_3_3`), allowing the user to easily express dependencies with a `package()` macro
    // without knowing the version in advance.
    trace!("Resolving transitive dependencies");
    let consolidator = resolver.resolve()?;
    trace!("Consolidating overrides");
    let renderer = consolidator.consolidate()?;

    renderer.render(&opt.repository_dir)?;

    let lockfile = &opt.lockfile;

    if opt.update_lockfile {
        if let Some(lockfile) = lockfile.as_ref() {
            renderer
                .render_lockfile(lockfile)
                .context("Failed to update lockfile")?;
        }
    }

    Ok(())
}
<commit_msg>Fix up formatting of error message (#735)<commit_after>use std::path::{Path, PathBuf};

use anyhow::{anyhow, Context};
use crate_universe_resolver::{config::Config, renderer::Renderer};
use indoc::indoc;
use log::*;
use structopt::StructOpt;

// Options which don't affect the contents of the generated should be on this struct.
// These fields are not factored into cache keys.
//
// Anything which affects the contents of the generated output should live on `config::Config`.
#[derive(StructOpt)]
struct Opt {
    #[structopt(long)]
    repo_name: String,
    #[structopt(long = "input_path", parse(from_os_str))]
    input_path: PathBuf,
    #[structopt(long = "repository_dir", parse(from_os_str))]
    repository_dir: PathBuf,
    #[structopt(long = "lockfile", parse(from_os_str))]
    lockfile: Option<PathBuf>,
    #[structopt(long = "update-lockfile")]
    update_lockfile: bool,
}

fn main() -> anyhow::Result<()> {
    env_logger::init();

    let opt = Opt::from_args();
    trace!("Parsing config from {:?}", opt.input_path);

    let config: Config = {
        let config_file = std::fs::File::open(&opt.input_path)
            .with_context(|| format!("Failed to open config file at {:?}", opt.input_path))?;
        serde_json::from_reader(config_file)
            .with_context(|| format!("Failed to parse config file {:?}", opt.input_path))?
    };

    let lockfile = &opt.lockfile;
    if opt.update_lockfile {
        if lockfile.is_none() {
            eprintln!("Not updating lockfile for `crate_universe` repository with name \"{}\" because it has no `lockfile` attribute.", opt.repo_name);
        }
    } else if let Some(lockfile) = lockfile {
        return reuse_lockfile(config, &lockfile, &opt);
    }

    generate_dependencies(config, &opt)
}

fn reuse_lockfile(config: Config, lockfile: &Path, opt: &Opt) -> anyhow::Result<()> {
    trace!("Preprocessing config");
    let repository_name = config.repository_name.clone();

    let mut resolver = config.preprocess()?;

    let renderer = Renderer::new_from_lockfile(lockfile)?;

    // TODO: Add lockfile versioning and check that here

    if !renderer.matches_digest(&resolver.digest()?) {
        return Err(anyhow!(
            indoc! { r#"
            "rules_rust_external: Lockfile at {} is out of date, please either:
            1. Re-run bazel with the environment variable `RULES_RUST_REPIN=true`, to update the lockfile.
            2. Remove the `lockfile` attribute from the `crate_universe` repository rule with name `{}` to use floating dependency versions.
        "# },
            lockfile.display(),
            repository_name,
        ));
    }

    renderer.render(&opt.repository_dir)
}

fn generate_dependencies(config: Config, opt: &Opt) -> anyhow::Result<()> {
    trace!("Preprocessing config");
    let resolver = config.preprocess()?;

    // This will contain the mapping of the workspace member (i.e. toplevel) packages' direct
    // dependencies package names to their package Bazel repository name (e.g. `bzip2 ->
    // bzip2__0_3_3`), allowing the user to easily express dependencies with a `package()` macro
    // without knowing the version in advance.
    trace!("Resolving transitive dependencies");
    let consolidator = resolver.resolve()?;
    trace!("Consolidating overrides");
    let renderer = consolidator.consolidate()?;

    renderer.render(&opt.repository_dir)?;

    let lockfile = &opt.lockfile;

    if opt.update_lockfile {
        if let Some(lockfile) = lockfile.as_ref() {
            renderer
                .render_lockfile(lockfile)
                .context("Failed to update lockfile")?;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>#![warn(clippy::all, rust_2018_idioms)]

use chrono::prelude::Utc;
use hmac::{Hmac, Mac, NewMac};
use reqwest::{
    blocking::{Body, Client, Response},
    header,
};
use sha1::Sha1;
use std::time::Duration;

pub use reqwest::Error;

#[derive(Clone, Debug)]
pub struct Bucket {
    name: String,
    region: Option<String>,
    access_key: String,
    secret_key: String,
    proto: String,
}

impl Bucket {
    pub fn new(
        name: String,
        region: Option<String>,
        access_key: String,
        secret_key: String,
        proto: &str,
    ) -> Bucket {
        Bucket {
            name,
            region,
            access_key,
            secret_key,
            proto: proto.to_string(),
        }
    }

    pub fn put<R: std::io::Read + Send + 'static>(
        &self,
        client: &Client,
        path: &str,
        content: R,
        content_length: u64,
        content_type: &str,
        extra_headers: header::HeaderMap,
    ) -> Result<Response, Error> {
        let path = path.strip_prefix('/').unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("PUT", &date, path, "", content_type);
        let url = self.url(path);

        client
            .put(&url)
            .header(header::AUTHORIZATION, auth)
            .header(header::CONTENT_TYPE, content_type)
            .header(header::DATE, date)
            .header(header::USER_AGENT, "crates.io (https://crates.io)")
            .headers(extra_headers)
            .body(Body::sized(content, content_length))
            .timeout(Duration::from_secs(60))
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn delete(&self, client: &Client, path: &str) -> Result<Response, Error> {
        let path = path.strip_prefix('/').unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("DELETE", &date, path, "", "");
        let url = self.url(path);

        client
            .delete(&url)
            .header(header::DATE, date)
            .header(header::AUTHORIZATION, auth)
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn host(&self) -> String {
        format!(
            "{}.s3{}.amazonaws.com",
            self.name,
            match self.region {
                Some(ref r) if !r.is_empty() => format!("-{}", r),
                Some(_) => String::new(),
                None => String::new(),
            }
        )
    }

    fn auth(&self, verb: &str, date: &str, path: &str, md5: &str, content_type: &str) -> String {
        let string = format!(
            "{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
            verb = verb,
            md5 = md5,
            ty = content_type,
            date = date,
            headers = "",
            resource = format!("/{}/{}", self.name, path)
        );
        let signature = {
            let key = self.secret_key.as_bytes();
            let mut h = Hmac::<Sha1>::new_varkey(key).expect("HMAC can take key of any size");
            h.update(string.as_bytes());
            let res = h.finalize().into_bytes();
            base64::encode(&res)
        };
        format!("AWS {}:{}", self.access_key, signature)
    }

    fn url(&self, path: &str) -> String {
        format!("{}://{}/{}", self.proto, self.host(), path)
    }
}
<commit_msg>s3: Adjust to new `hmac` API name<commit_after>#![warn(clippy::all, rust_2018_idioms)]

use chrono::prelude::Utc;
use hmac::{Hmac, Mac, NewMac};
use reqwest::{
    blocking::{Body, Client, Response},
    header,
};
use sha1::Sha1;
use std::time::Duration;

pub use reqwest::Error;

#[derive(Clone, Debug)]
pub struct Bucket {
    name: String,
    region: Option<String>,
    access_key: String,
    secret_key: String,
    proto: String,
}

impl Bucket {
    pub fn new(
        name: String,
        region: Option<String>,
        access_key: String,
        secret_key: String,
        proto: &str,
    ) -> Bucket {
        Bucket {
            name,
            region,
            access_key,
            secret_key,
            proto: proto.to_string(),
        }
    }

    pub fn put<R: std::io::Read + Send + 'static>(
        &self,
        client: &Client,
        path: &str,
        content: R,
        content_length: u64,
        content_type: &str,
        extra_headers: header::HeaderMap,
    ) -> Result<Response, Error> {
        let path = path.strip_prefix('/').unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("PUT", &date, path, "", content_type);
        let url = self.url(path);

        client
            .put(&url)
            .header(header::AUTHORIZATION, auth)
            .header(header::CONTENT_TYPE, content_type)
            .header(header::DATE, date)
            .header(header::USER_AGENT, "crates.io (https://crates.io)")
            .headers(extra_headers)
            .body(Body::sized(content, content_length))
            .timeout(Duration::from_secs(60))
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn delete(&self, client: &Client, path: &str) -> Result<Response, Error> {
        let path = path.strip_prefix('/').unwrap_or(path);
        let date = Utc::now().to_rfc2822();
        let auth = self.auth("DELETE", &date, path, "", "");
        let url = self.url(path);

        client
            .delete(&url)
            .header(header::DATE, date)
            .header(header::AUTHORIZATION, auth)
            .send()?
            .error_for_status()
            .map_err(Into::into)
    }

    pub fn host(&self) -> String {
        format!(
            "{}.s3{}.amazonaws.com",
            self.name,
            match self.region {
                Some(ref r) if !r.is_empty() => format!("-{}", r),
                Some(_) => String::new(),
                None => String::new(),
            }
        )
    }

    fn auth(&self, verb: &str, date: &str, path: &str, md5: &str, content_type: &str) -> String {
        let string = format!(
            "{verb}\n{md5}\n{ty}\n{date}\n{headers}{resource}",
            verb = verb,
            md5 = md5,
            ty = content_type,
            date = date,
            headers = "",
            resource = format!("/{}/{}", self.name, path)
        );
        let signature = {
            let key = self.secret_key.as_bytes();
            let mut h = Hmac::<Sha1>::new_from_slice(key).expect("HMAC can take key of any size");
            h.update(string.as_bytes());
            let res = h.finalize().into_bytes();
            base64::encode(&res)
        };
        format!("AWS {}:{}", self.access_key, signature)
    }

    fn url(&self, path: &str) -> String {
        format!("{}://{}/{}", self.proto, self.host(), path)
    }
}
<|endoftext|>


<commit_before>#![feature(link_args)]
#![no_main]

#[link_args = "-s MODULARIZE=1 -s EXPORT_NAME='LiveSplitCore' -Oz -s TOTAL_MEMORY=33554432 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN_METHOD='native-wasm'"]
extern "C" {}

extern crate livesplit_core_capi;
<commit_msg>Suppress unused crate warning by reexporting<commit_after>#![feature(link_args)]
#![no_main]

#[link_args = "-s MODULARIZE=1 -s EXPORT_NAME='LiveSplitCore' -Oz -s TOTAL_MEMORY=33554432 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN_METHOD='native-wasm'"]
extern "C" {}

extern crate livesplit_core_capi;

pub use livesplit_core_capi::*;
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::{
        types::{EncodingOptions, EncodingType, Error, KeyType, PromptOptions},
        utils::{append_file_extension, prompt_yes, to_common_success_result},
    },
    CliResult,
};
use aptos_crypto::{
    ed25519, ed25519::Ed25519PrivateKey, x25519, PrivateKey, Uniform, ValidCryptoMaterial,
    ValidCryptoMaterialStringExt,
};
use clap::{Parser, Subcommand};
use rand::SeedableRng;
use std::{
    fs::File,
    io::Write,
    path::{Path, PathBuf},
};

pub const PUBLIC_KEY_EXTENSION: &str = ".pub";

/// CLI tool for generating, inspecting, and interacting with keys.
#[derive(Debug, Subcommand)]
pub enum KeyTool {
    Generate(GenerateKey),
}

impl KeyTool {
    pub async fn execute(self) -> CliResult {
        match self {
            KeyTool::Generate(tool) => to_common_success_result(tool.execute()),
        }
    }
}

/// Generates a `x25519` or `ed25519` key.
///
/// This can be used for generating an identity.
#[derive(Debug, Parser)]
pub struct GenerateKey {
    /// Key type: `x25519` or `ed25519`
    #[clap(long, default_value = "ed25519")]
    key_type: KeyType,
    #[clap(flatten)]
    save_params: SaveKey,
}

impl GenerateKey {
    pub(crate) fn execute(self) -> Result<(), Error> {
        self.save_params.check_key_file()?;

        // Generate a ed25519 key
        let ed25519_key = Self::generate_ed25519_in_memory();

        // Convert it to the appropriate type and save it
        match self.key_type {
            KeyType::X25519 => {
                let private_key =
                    x25519::PrivateKey::from_ed25519_private_bytes(&ed25519_key.to_bytes())
                        .map_err(|err| Error::UnexpectedError(err.to_string()))?;
                self.save_params.save_key(&private_key, "x22519")
            }
            KeyType::Ed25519 => self.save_params.save_key(&ed25519_key, "ed22519"),
        }
    }

    /// A test friendly typed key generation for x25519 keys.
    pub fn generate_x25519(
        encoding_type: EncodingType,
        key_file: &Path,
    ) -> Result<(x25519::PrivateKey, x25519::PublicKey), Error> {
        let args = format!(
            "generate --key-type {key_type:?} --key-file {key_file} --encoding {encoding_type:?} --assume-yes",
            key_type = KeyType::X25519,
            key_file = key_file.to_str().unwrap(),
            encoding_type = encoding_type,
        );
        let command = GenerateKey::parse_from(args.split_whitespace());
        command.execute()?;
        Ok((
            load_key(key_file, encoding_type)?,
            load_key(
                &append_file_extension(key_file, PUBLIC_KEY_EXTENSION)?,
                encoding_type,
            )?,
        ))
    }

    /// A test friendly typed key generation for e25519 keys.
    pub fn generate_ed25519(
        encoding_type: EncodingType,
        key_file: &Path,
    ) -> Result<(ed25519::Ed25519PrivateKey, ed25519::Ed25519PublicKey), Error> {
        let args = format!(
            "generate --key-type {key_type:?} --key-file {key_file} --encoding {encoding_type:?} --assume-yes",
            key_type = KeyType::Ed25519,
            key_file = key_file.to_str().unwrap(),
            encoding_type = encoding_type,
        );
        let command = GenerateKey::parse_from(args.split_whitespace());
        command.execute()?;
        Ok((
            load_key(key_file, encoding_type)?,
            load_key(
                &append_file_extension(key_file, PUBLIC_KEY_EXTENSION)?,
                encoding_type,
            )?,
        ))
    }

    /// Generates an `Ed25519PrivateKey` without saving it to disk
    pub fn generate_ed25519_in_memory() -> ed25519::Ed25519PrivateKey {
        let mut rng = rand::rngs::StdRng::from_entropy();
        Ed25519PrivateKey::generate(&mut rng)
    }
}

#[derive(Debug, Parser)]
pub struct SaveKey {
    /// Private key output file name.  Public key will be saved to <key-file>.pub
    #[clap(long, parse(from_os_str))]
    key_file: PathBuf,
    #[clap(flatten)]
    encoding_options: EncodingOptions,
    #[clap(flatten)]
    prompt_options: PromptOptions,
}

impl SaveKey {
    /// Public key file name
    fn public_key_file(&self) -> Result<PathBuf, Error> {
        append_file_extension(&self.key_file, PUBLIC_KEY_EXTENSION)
    }

    /// Check if the key file exists already
    pub fn check_key_file(&self) -> Result<(), Error> {
        // Check if file already exists
        check_if_file_exists(&self.key_file, self.prompt_options.assume_yes)?;
        check_if_file_exists(&self.public_key_file()?, self.prompt_options.assume_yes)
    }

    /// Saves a key to a file encoded in a string
    pub fn save_key<Key: PrivateKey + ValidCryptoMaterial>(
        &self,
        key: &Key,
        key_name: &'static str,
    ) -> Result<(), Error> {
        let encoded_private_key = encode_key(self.encoding_options.encoding, key, key_name)?;
        let encoded_public_key =
            encode_key(self.encoding_options.encoding, &key.public_key(), key_name)?;

        // Write private and public keys to files
        write_to_file(&self.key_file, key_name, encoded_private_key)?;
        write_to_file(&self.public_key_file()?, key_name, encoded_public_key)
    }
}

/// Encodes `Key` into one of the `EncodingType`s
pub fn encode_key<Key: ValidCryptoMaterial>(
    encoding: EncodingType,
    key: &Key,
    key_name: &str,
) -> Result<Vec<u8>, Error> {
    Ok(match encoding {
        EncodingType::Hex => hex::encode_upper(key.to_bytes()).into_bytes(),
        EncodingType::BCS => {
            bcs::to_bytes(key).map_err(|err| Error::BCS(key_name.to_string(), err))?
        }
        EncodingType::Base64 => base64::encode(key.to_bytes()).into_bytes(),
    })
}

/// Write a `Vec<u8>` to a file
fn write_to_file(key_file: &Path, key_name: &str, encoded_key: Vec<u8>) -> Result<(), Error> {
    let mut file = File::create(key_file).map_err(|e| Error::IO(key_name.to_string(), e))?;
    file.write_all(&encoded_key)
        .map_err(|e| Error::IO(key_name.to_string(), e))
}

/// Checks if a file exists, being overridden by `--assume-yes`
fn check_if_file_exists(file: &Path, assume_yes: bool) -> Result<(), Error> {
    if file.exists()
        && !assume_yes
        && !prompt_yes(
            format!(
                "{:?} already exists, are you sure you want to overwrite it?",
                file.as_os_str()
            )
            .as_str(),
        )
    {
        Err(Error::AbortedError)
    } else {
        Ok(())
    }
}

/// Loads a key from a file
pub fn load_key<Key: ValidCryptoMaterial>(
    path: &Path,
    encoding: EncodingType,
) -> Result<Key, Error> {
    let data = std::fs::read(&path).map_err(|err| {
        Error::UnableToReadFile(path.to_str().unwrap().to_string(), err.to_string())
    })?;

    match encoding {
        EncodingType::BCS => {
            bcs::from_bytes(&data).map_err(|err| Error::BCS("Key".to_string(), err))
        }
        EncodingType::Hex => {
            let hex_string = String::from_utf8(data).unwrap();
            Key::from_encoded_string(hex_string.trim())
                .map_err(|err| Error::UnableToParse("Key", err.to_string()))
        }
        EncodingType::Base64 => {
            let string = String::from_utf8(data).unwrap();
            let bytes = base64::decode(string.trim())
                .map_err(|err| Error::UnableToParse("Key", err.to_string()))?;
            Key::try_from(bytes.as_slice())
                .map_err(|err| Error::UnexpectedError(format!("Failed to parse key {}", err)))
        }
    }
}
<commit_msg>[aptos-cli] Make output of key generate more user friendly<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::{
    common::{
        types::{EncodingOptions, EncodingType, Error, KeyType, PromptOptions},
        utils::{append_file_extension, prompt_yes},
    },
    CliResult,
};
use aptos_crypto::{
    ed25519, ed25519::Ed25519PrivateKey, x25519, PrivateKey, Uniform, ValidCryptoMaterial,
    ValidCryptoMaterialStringExt,
};
use clap::{Parser, Subcommand};
use rand::SeedableRng;
use std::{
    fs::File,
    io::Write,
    path::{Path, PathBuf},
};
use std::collections::HashMap;
use crate::common::utils::to_common_result;

pub const PUBLIC_KEY_EXTENSION: &str = ".pub";

/// CLI tool for generating, inspecting, and interacting with keys.
#[derive(Debug, Subcommand)]
pub enum KeyTool {
    Generate(GenerateKey),
}

impl KeyTool {
    pub async fn execute(self) -> CliResult {
        match self {
            KeyTool::Generate(tool) => to_common_result(tool.execute()),
        }
    }
}

/// Generates a `x25519` or `ed25519` key.
///
/// This can be used for generating an identity.
#[derive(Debug, Parser)]
pub struct GenerateKey {
    /// Key type: `x25519` or `ed25519`
    #[clap(long, default_value = "ed25519")]
    key_type: KeyType,
    #[clap(flatten)]
    save_params: SaveKey,
}

impl GenerateKey {
    pub(crate) fn execute(self) -> Result<HashMap<&'static str, PathBuf>, Error> {
        self.save_params.check_key_file()?;

        // Generate a ed25519 key
        let ed25519_key = Self::generate_ed25519_in_memory();

        // Convert it to the appropriate type and save it
        match self.key_type {
            KeyType::X25519 => {
                let private_key =
                    x25519::PrivateKey::from_ed25519_private_bytes(&ed25519_key.to_bytes())
                        .map_err(|err| Error::UnexpectedError(err.to_string()))?;
                self.save_params.save_key(&private_key, "x22519")
            }
            KeyType::Ed25519 => self.save_params.save_key(&ed25519_key, "ed22519"),
        }
    }

    /// A test friendly typed key generation for x25519 keys.
    pub fn generate_x25519(
        encoding_type: EncodingType,
        key_file: &Path,
    ) -> Result<(x25519::PrivateKey, x25519::PublicKey), Error> {
        let args = format!(
            "generate --key-type {key_type:?} --key-file {key_file} --encoding {encoding_type:?} --assume-yes",
            key_type = KeyType::X25519,
            key_file = key_file.to_str().unwrap(),
            encoding_type = encoding_type,
        );
        let command = GenerateKey::parse_from(args.split_whitespace());
        command.execute()?;
        Ok((
            load_key(key_file, encoding_type)?,
            load_key(
                &append_file_extension(key_file, PUBLIC_KEY_EXTENSION)?,
                encoding_type,
            )?,
        ))
    }

    /// A test friendly typed key generation for e25519 keys.
    pub fn generate_ed25519(
        encoding_type: EncodingType,
        key_file: &Path,
    ) -> Result<(ed25519::Ed25519PrivateKey, ed25519::Ed25519PublicKey), Error> {
        let args = format!(
            "generate --key-type {key_type:?} --key-file {key_file} --encoding {encoding_type:?} --assume-yes",
            key_type = KeyType::Ed25519,
            key_file = key_file.to_str().unwrap(),
            encoding_type = encoding_type,
        );
        let command = GenerateKey::parse_from(args.split_whitespace());
        command.execute()?;
        Ok((
            load_key(key_file, encoding_type)?,
            load_key(
                &append_file_extension(key_file, PUBLIC_KEY_EXTENSION)?,
                encoding_type,
            )?,
        ))
    }

    /// Generates an `Ed25519PrivateKey` without saving it to disk
    pub fn generate_ed25519_in_memory() -> ed25519::Ed25519PrivateKey {
        let mut rng = rand::rngs::StdRng::from_entropy();
        Ed25519PrivateKey::generate(&mut rng)
    }
}

#[derive(Debug, Parser)]
pub struct SaveKey {
    /// Private key output file name.  Public key will be saved to <key-file>.pub
    #[clap(long, parse(from_os_str))]
    key_file: PathBuf,
    #[clap(flatten)]
    encoding_options: EncodingOptions,
    #[clap(flatten)]
    prompt_options: PromptOptions,
}

impl SaveKey {
    /// Public key file name
    fn public_key_file(&self) -> Result<PathBuf, Error> {
        append_file_extension(&self.key_file, PUBLIC_KEY_EXTENSION)
    }

    /// Check if the key file exists already
    pub fn check_key_file(&self) -> Result<(), Error> {
        // Check if file already exists
        check_if_file_exists(&self.key_file, self.prompt_options.assume_yes)?;
        check_if_file_exists(&self.public_key_file()?, self.prompt_options.assume_yes)
    }

    /// Saves a key to a file encoded in a string
    pub fn save_key<Key: PrivateKey + ValidCryptoMaterial>(
        &self,
        key: &Key,
        key_name: &'static str,
    ) -> Result<HashMap<&'static str, PathBuf>, Error> {
        let encoded_private_key = encode_key(self.encoding_options.encoding, key, key_name)?;
        let encoded_public_key =
            encode_key(self.encoding_options.encoding, &key.public_key(), key_name)?;

        // Write private and public keys to files
        let public_key_file = self.public_key_file()?;
        write_to_file(&self.key_file, key_name, encoded_private_key)?;
        write_to_file(&public_key_file, key_name, encoded_public_key)?;

        let mut map = HashMap::new();
        map.insert("PrivateKey Path", self.key_file.clone());
        map.insert("PublicKey Path", public_key_file);
        Ok(map)
    }
}

/// Encodes `Key` into one of the `EncodingType`s
pub fn encode_key<Key: ValidCryptoMaterial>(
    encoding: EncodingType,
    key: &Key,
    key_name: &str,
) -> Result<Vec<u8>, Error> {
    Ok(match encoding {
        EncodingType::Hex => hex::encode_upper(key.to_bytes()).into_bytes(),
        EncodingType::BCS => {
            bcs::to_bytes(key).map_err(|err| Error::BCS(key_name.to_string(), err))?
        }
        EncodingType::Base64 => base64::encode(key.to_bytes()).into_bytes(),
    })
}

/// Write a `Vec<u8>` to a file
fn write_to_file(key_file: &Path, key_name: &str, encoded_key: Vec<u8>) -> Result<(), Error> {
    let mut file = File::create(key_file).map_err(|e| Error::IO(key_name.to_string(), e))?;
    file.write_all(&encoded_key)
        .map_err(|e| Error::IO(key_name.to_string(), e))
}

/// Checks if a file exists, being overridden by `--assume-yes`
fn check_if_file_exists(file: &Path, assume_yes: bool) -> Result<(), Error> {
    if file.exists()
        && !assume_yes
        && !prompt_yes(
            format!(
                "{:?} already exists, are you sure you want to overwrite it?",
                file.as_os_str()
            )
            .as_str(),
        )
    {
        Err(Error::AbortedError)
    } else {
        Ok(())
    }
}

/// Loads a key from a file
pub fn load_key<Key: ValidCryptoMaterial>(
    path: &Path,
    encoding: EncodingType,
) -> Result<Key, Error> {
    let data = std::fs::read(&path).map_err(|err| {
        Error::UnableToReadFile(path.to_str().unwrap().to_string(), err.to_string())
    })?;

    match encoding {
        EncodingType::BCS => {
            bcs::from_bytes(&data).map_err(|err| Error::BCS("Key".to_string(), err))
        }
        EncodingType::Hex => {
            let hex_string = String::from_utf8(data).unwrap();
            Key::from_encoded_string(hex_string.trim())
                .map_err(|err| Error::UnableToParse("Key", err.to_string()))
        }
        EncodingType::Base64 => {
            let string = String::from_utf8(data).unwrap();
            let bytes = base64::decode(string.trim())
                .map_err(|err| Error::UnableToParse("Key", err.to_string()))?;
            Key::try_from(bytes.as_slice())
                .map_err(|err| Error::UnexpectedError(format!("Failed to parse key {}", err)))
        }
    }
}
<|endoftext|>


<commit_before>use traits::*;

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum BFTokenType {
    IncrementPtr(usize),      // >
    DecrementPtr(usize),      // <
    IncrementData(usize),     // +
    DecrementData(usize),     // -
    Output,                   // .
    Input,                    // ,

    // These store their corresponding tokens
    //  aka LoopStart stores the position of
    //  the matching LoopEnd and vice versa.
    LoopStart(usize),         // [
    LoopEnd(usize),           // ]

    // Optimised instructions
    SetCurrent(i8),           // Sets the current cell to value
    AddCurrentUp(usize),      // Adds current cell to cell in [current + value]
    AddCurrentDown(usize)     // Adds current cell to cell in [current - value]
}

#[derive(Clone, Debug, Copy)]
pub struct BFToken {
    pub token_type : BFTokenType,

    // Used for matching brackets
    pub pos : usize
}

pub struct BFLexer {
}

impl Lexer<Vec<BFToken>> for BFLexer {

    fn parse(input_string:String) -> LexResult<Vec<BFToken>> {
        // Import enum -> Allows for using enum values without
        //  BFTokenType:: prefix
        use self::BFTokenType::*;

        // Create empty vector
        let mut tokens : Vec<BFToken> = vec![];

        // Store the index of the token in the vector
        let mut pos : usize = 0;

        // This stores the positions of open brackets
        // This is used to match up bracket pairs
        //  so that they can jump to each other in O(1)
        let mut loop_stack : Vec<usize> = vec![];

        // Store the previous 5 tokens, these are used
        //  for optimisations.
        let mut last_tokens = [BFToken { pos : 0, token_type : Input }; 5];

        // Loop through each character
        for character in input_string.chars() {
            // Match our character to a TokenType.
            let token_type = match character {
                '>' => {
                    // Batch up all the '>' tokens
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let IncrementPtr(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    IncrementPtr(new_x)
                },
                '<' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let DecrementPtr(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    DecrementPtr(new_x)
                },
                '+' =>  {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let IncrementData(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    IncrementData(new_x)
                },
                '-' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let DecrementData(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    DecrementData(new_x)
                },
                '.' => Output,
                ',' => Input,
                '[' => {
                    // Push this pos onto stack
                    loop_stack.push(pos);

                    // Store temp value of 0 for now - will be updated
                    //  once we know matching ]
                    LoopStart(0)
                },
                ']' => {

                    // Get matching bracket.
                    let index = loop_stack.pop().expect("Bracket mismatch");
                    let mut ret_token : BFTokenType = LoopEnd(index);

                    // Update it's data position to this ] token
                    tokens[index].token_type = LoopStart(pos);

                    match last_tokens[0].token_type {
                        // This currently checks for [-] or [+] and replaces
                        //  those with a set current cell to 0 instruction.
                        IncrementData(_)
                        | DecrementData(_) => {
                            if let LoopStart(_) = last_tokens[1].token_type {
                                ret_token = SetCurrent(0);
                                tokens.pop();
                                tokens.pop();
                                pos-=2;
                            }
                        },

                        // Optimisation for [-<+>] or [->+<] pattern.
                        // These loops will add the current cell value
                        //  to the cell value offset by the amount of
                        //  ptr increments '>' and '<'.
                        //
                        // Examples:
                        //
                        //  [->+<]         adds mem[current] to mem[current+1]
                        //
                        //  [->>>>+<<<<]   adds mem[current] to mem[current+4]
                        //
                        // Note that due to the combination optimisation
                        //  this only needs to check for [->+<] or [-<+>]
                        DecrementPtr(x)
                        | IncrementPtr(x) => {
                            if let IncrementData(a) = last_tokens[1].token_type {
                                match last_tokens[2].token_type {
                                    IncrementPtr(y)
                                    | DecrementPtr(y) => {
                                        if x == y {
                                            if let DecrementData(b) = last_tokens[3].token_type  {
                                                if a == b {
                                                    if let LoopStart(_) = last_tokens[4].token_type {
                                                        if last_tokens[0].token_type == DecrementPtr(x) {
                                                            ret_token = AddCurrentUp(x);
                                                        } else {
                                                            ret_token = AddCurrentDown(x);
                                                        }
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        pos-=5;
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    _ => { }
                                }
                            };
                        },

                        // Empty Loop
                        LoopStart(_) => {
                            tokens.pop();
                            pos-=1;
                            continue;
                        },

                        _ => { }
                    }

                    ret_token
                },

                // BF is a very simple language - if there is an
                //  unrecognised character, it is ignored.
                _ => continue
            };

            let mut i = 1;
            // Recopy last tokens instead of shifting as they
            //  may have chagned.
            while i < 5 && pos > i-1 {
                last_tokens[i] = tokens[pos-i].clone();
                i+=1;
            }

            pos+=1;

            // Add it to the list of tokens
            let token = BFToken { token_type : token_type, pos : pos};

            last_tokens[0] = token.clone();

            tokens.push(token);
        }

        // No way for this to currently fail.
        LexResult::Success(tokens)
    }
}
<commit_msg>Even more explanation for cell addition optimisation<commit_after>use traits::*;

#[derive(PartialEq, Clone, Debug, Copy)]
pub enum BFTokenType {
    IncrementPtr(usize),      // >
    DecrementPtr(usize),      // <
    IncrementData(usize),     // +
    DecrementData(usize),     // -
    Output,                   // .
    Input,                    // ,

    // These store their corresponding tokens
    //  aka LoopStart stores the position of
    //  the matching LoopEnd and vice versa.
    LoopStart(usize),         // [
    LoopEnd(usize),           // ]

    // Optimised instructions
    SetCurrent(i8),           // Sets the current cell to value
    AddCurrentUp(usize),      // Adds current cell to cell in [current + value]
    AddCurrentDown(usize)     // Adds current cell to cell in [current - value]
}

#[derive(Clone, Debug, Copy)]
pub struct BFToken {
    pub token_type : BFTokenType,

    // Used for matching brackets
    pub pos : usize
}

pub struct BFLexer {
}

impl Lexer<Vec<BFToken>> for BFLexer {

    fn parse(input_string:String) -> LexResult<Vec<BFToken>> {
        // Import enum -> Allows for using enum values without
        //  BFTokenType:: prefix
        use self::BFTokenType::*;

        // Create empty vector
        let mut tokens : Vec<BFToken> = vec![];

        // Store the index of the token in the vector
        let mut pos : usize = 0;

        // This stores the positions of open brackets
        // This is used to match up bracket pairs
        //  so that they can jump to each other in O(1)
        let mut loop_stack : Vec<usize> = vec![];

        // Store the previous 5 tokens, these are used
        //  for optimisations.
        let mut last_tokens = [BFToken { pos : 0, token_type : Input }; 5];

        // Loop through each character
        for character in input_string.chars() {
            // Match our character to a TokenType.
            let token_type = match character {
                '>' => {
                    // Batch up all the '>' tokens
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let IncrementPtr(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    IncrementPtr(new_x)
                },
                '<' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let DecrementPtr(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    DecrementPtr(new_x)
                },
                '+' =>  {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let IncrementData(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    IncrementData(new_x)
                },
                '-' => {
                    let mut new_x = 1;
                    if last_tokens[0].pos > 0 {
                        if let DecrementData(x) = last_tokens[0].token_type {
                            tokens.pop();
                            pos-=1;
                            new_x += x;
                        }
                    }
                    DecrementData(new_x)
                },
                '.' => Output,
                ',' => Input,
                '[' => {
                    // Push this pos onto stack
                    loop_stack.push(pos);

                    // Store temp value of 0 for now - will be updated
                    //  once we know matching ]
                    LoopStart(0)
                },
                ']' => {

                    // Get matching bracket.
                    let index = loop_stack.pop().expect("Bracket mismatch");
                    let mut ret_token : BFTokenType = LoopEnd(index);

                    // Update it's data position to this ] token
                    tokens[index].token_type = LoopStart(pos);

                    match last_tokens[0].token_type {
                        // This currently checks for [-] or [+] and replaces
                        //  those with a set current cell to 0 instruction.
                        IncrementData(_)
                        | DecrementData(_) => {
                            if let LoopStart(_) = last_tokens[1].token_type {
                                ret_token = SetCurrent(0);
                                tokens.pop();
                                tokens.pop();
                                pos-=2;
                            }
                        },

                        // Optimisation for [-<+>] or [->+<] pattern.
                        // These loops will add the current cell value
                        //  to the cell value offset by the amount of
                        //  ptr increments '>' and '<'.
                        // As it adds to the offset cell, it takes from
                        //  the current cell. This will loop until the
                        //  current cell is 0.
                        // So it can be equated to addition and setting
                        //  the current value to 0
                        //
                        // Examples:
                        //
                        //  [->+<]         adds mem[current] to mem[current+1]
                        //                 sets mem[current] to 0
                        //
                        //  [->>>>+<<<<]   adds mem[current] to mem[current+4]
                        //                 sets mem[current] to 0
                        //
                        // Note that due to the combination optimisation
                        //  this only needs to check for [->+<] or [-<+>]
                        DecrementPtr(x)
                        | IncrementPtr(x) => {
                            if let IncrementData(a) = last_tokens[1].token_type {
                                match last_tokens[2].token_type {
                                    IncrementPtr(y)
                                    | DecrementPtr(y) => {
                                        if x == y {
                                            if let DecrementData(b) = last_tokens[3].token_type  {
                                                if a == b {
                                                    if let LoopStart(_) = last_tokens[4].token_type {
                                                        if last_tokens[0].token_type == DecrementPtr(x) {
                                                            ret_token = AddCurrentUp(x);
                                                        } else {
                                                            ret_token = AddCurrentDown(x);
                                                        }
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        tokens.pop();
                                                        pos-=5;
                                                    }
                                                }
                                            }
                                        }
                                    },
                                    _ => { }
                                }
                            };
                        },

                        // Empty Loop
                        LoopStart(_) => {
                            tokens.pop();
                            pos-=1;
                            continue;
                        },

                        _ => { }
                    }

                    ret_token
                },

                // BF is a very simple language - if there is an
                //  unrecognised character, it is ignored.
                _ => continue
            };

            let mut i = 1;
            // Recopy last tokens instead of shifting as they
            //  may have chagned.
            while i < 5 && pos > i-1 {
                last_tokens[i] = tokens[pos-i].clone();
                i+=1;
            }

            pos+=1;

            // Add it to the list of tokens
            let token = BFToken { token_type : token_type, pos : pos};

            last_tokens[0] = token.clone();

            tokens.push(token);
        }

        // No way for this to currently fail.
        LexResult::Success(tokens)
    }
}
<|endoftext|>


<commit_before>use cookie_factory::*;
use elements::{Seek, SeekHead, SegmentElement};
use super::ebml::{vint_size, gen_vint, gen_vid, gen_uint};

pub fn seek_size(s: &Seek) -> u8 {
    // byte size of id (vid+size)+ data and position vid+size+int
    // FIXME: arbitrarily bad value
    vint_size(vint_size((s.id.len() + 10) as u64) as u64)
}

pub fn gen_segment<'a>(input: (&'a mut [u8], usize), s: &SegmentElement) -> Result<(&'a mut [u8], usize), GenError> {
  unimplemented!();
  /*do_gen!(input,
    gen_call!(gen_vid, 0x18538067) >>
    gen_call!(gen_vint, 4)
  )*/
}

pub fn gen_seek<'a>(input: (&'a mut [u8], usize),
                    s: &Seek)
                    -> Result<(&'a mut [u8], usize), GenError> {
    let capacity = 8 + 2 + vint_size(s.id.len() as u64) as u64 + s.id.len() as u64;

    gen_ebml_master!(input,
    0x4DBB, vint_size(capacity),
    gen_ebml_binary!(0x53AB, s.id) >>
    gen_ebml_uint!(0x53AC, s.position, vint_size(s.position))
  )
}

pub fn gen_seek_head<'a>(input: (&'a mut [u8], usize),
                         s: &SeekHead)
                         -> Result<(&'a mut [u8], usize), GenError> {
  let capacity = s.positions.iter().fold(0u64, |acc, seek| acc + 4 + 8 + 2 + vint_size(seek.id.len() as u64) as u64 + seek.id.len() as u64);
  println!("gen_seek_head: calculated capacity: {} -> {} bytes", capacity, vint_size(capacity));

  let byte_capacity = vint_size(capacity as u64);
  gen_ebml_master!(input,
    0x114D9B74, byte_capacity,
    gen_many_ref!(&s.positions, gen_seek)
  )
}

#[cfg(test)]
mod tests {
  use super::*;
  use nom::*;
  use std::iter::repeat;

  fn test_seek_head_serializer(mut seeks: Vec<(u64, Vec<u8>)>) -> bool {
    println!("testing for {:?}", seeks);
    if seeks.len() == 0 {
      return true;
    }

    for &(_, ref id) in seeks.iter() {
      println!("id: {}", id.to_hex(16));
      if id.len() == 0 {
        println!("id is empty, returning");
        return true;
      }
    }

    let capacity = seeks.iter().fold(0, |acc, &(_, ref v)| acc + 8 + v.len() + 100);
    println!("defining capacity as {}", capacity);

    let mut data = Vec::with_capacity(capacity);
    data.extend(repeat(0).take(capacity));

    let seek_head = SeekHead {
      positions: seeks.iter().cloned().map(|(position, id)| Seek { id, position }).collect()
    };

    {
      let gen_res = gen_seek_head((&mut data[..], 0), &seek_head);
      println!("gen_res: {:?}", gen_res);
    }
    //println!("{}", (&data[..]).to_hex(16));

    let parse_res = ::elements::segment_element(&data[..]);
    println!("parse_res: {:?}", parse_res);
    match parse_res {
      IResult::Done(rest, SegmentElement::SeekHead(o)) => {
        assert_eq!(seek_head, o);
        return true;
      },
      e => panic!(format!("parse error: {:?} for input: {:?}", e, seeks)),
    }

    false
  }

  quickcheck! {
    fn test_seek_head(seeks: Vec<(u64, Vec<u8>)>) -> bool {
      test_seek_head_serializer(seeks)
    }
  }
}
<commit_msg>mark invalid data as 'should_fail' in test<commit_after>use cookie_factory::*;
use elements::{Seek, SeekHead, SegmentElement};
use super::ebml::{vint_size, gen_vint, gen_vid, gen_uint};

pub fn seek_size(s: &Seek) -> u8 {
    // byte size of id (vid+size)+ data and position vid+size+int
    // FIXME: arbitrarily bad value
    vint_size(vint_size((s.id.len() + 10) as u64) as u64)
}

pub fn gen_segment<'a>(input: (&'a mut [u8], usize), s: &SegmentElement) -> Result<(&'a mut [u8], usize), GenError> {
  unimplemented!();
  /*do_gen!(input,
    gen_call!(gen_vid, 0x18538067) >>
    gen_call!(gen_vint, 4)
  )*/
}

pub fn gen_seek<'a>(input: (&'a mut [u8], usize),
                    s: &Seek)
                    -> Result<(&'a mut [u8], usize), GenError> {
    let capacity = 8 + 2 + vint_size(s.id.len() as u64) as u64 + s.id.len() as u64;

    gen_ebml_master!(input,
    0x4DBB, vint_size(capacity),
    gen_ebml_binary!(0x53AB, s.id) >>
    gen_ebml_uint!(0x53AC, s.position, vint_size(s.position))
  )
}

pub fn gen_seek_head<'a>(input: (&'a mut [u8], usize),
                         s: &SeekHead)
                         -> Result<(&'a mut [u8], usize), GenError> {
  let capacity = s.positions.iter().fold(0u64, |acc, seek| acc + 4 + 8 + 2 + vint_size(seek.id.len() as u64) as u64 + seek.id.len() as u64);
  println!("gen_seek_head: calculated capacity: {} -> {} bytes", capacity, vint_size(capacity));

  let byte_capacity = vint_size(capacity as u64);
  gen_ebml_master!(input,
    0x114D9B74, byte_capacity,
    gen_many_ref!(&s.positions, gen_seek)
  )
}

#[cfg(test)]
mod tests {
  use super::*;
  use nom::*;
  use std::iter::repeat;

  fn test_seek_head_serializer(mut seeks: Vec<(u64, Vec<u8>)>) -> bool {
    println!("testing for {:?}", seeks);

    let mut should_fail = false;
    if seeks.len() == 0 {
      should_fail = true;
    }

    for &(_, ref id) in seeks.iter() {
      println!("id: {}", id.to_hex(16));
      if id.len() == 0 {
        println!("id is empty, returning");
        return true;
        //should_fail = true;
      }
    }

    if should_fail {
      println!("the parser should fail");
    }

    let capacity = seeks.iter().fold(0, |acc, &(_, ref v)| acc + 8 + v.len() + 100);
    println!("defining capacity as {}", capacity);

    let mut data = Vec::with_capacity(capacity);
    data.extend(repeat(0).take(capacity));

    let seek_head = SeekHead {
      positions: seeks.iter().cloned().map(|(position, id)| Seek { id, position }).collect()
    };

    let ser_res = {
      let gen_res = gen_seek_head((&mut data[..], 0), &seek_head);
      println!("gen_res: {:?}", gen_res);
      if let Err(e) = gen_res {
        println!("gen_res is error: {:?}", e);
        println!("should fail: {:?}", should_fail);
        return should_fail;
        /*if should_fail {
          println!("should fail");
          return true;
        }*/
      }
    };

    println!("ser_res: {:?}", ser_res);

    let parse_res = ::elements::segment_element(&data[..]);
    println!("parse_res: {:?}", parse_res);
    match parse_res {
      IResult::Done(rest, SegmentElement::SeekHead(o)) => {
        if should_fail {
          println!("parser should have failed on input for {:?}", seek_head);
          println!("{}", (&data[..]).to_hex(16));
          return false;
        }

        assert_eq!(seek_head, o);
        return true;
      },
      e => {
        if should_fail {
          return true;
        }

        panic!(format!("parse error: {:?} for input: {:?}", e, seeks))
      },
    }

    false
  }

  quickcheck! {
    fn test_seek_head(seeks: Vec<(u64, Vec<u8>)>) -> bool {
      test_seek_head_serializer(seeks)
    }
  }
}
<|endoftext|>


<commit_before>use num::complex::Complex;
use super::Simd;
use simd::x86::avx::{f32x8,f64x4,AvxF32x8,AvxF64x4};
use std::mem;

pub type Reg32 = f32x8;

pub type Reg64 = f64x4;

impl Simd<f32> for f32x8
{
    type Array = [f32; 8];

    fn to_array(self) -> Self::Array {
        let mut target = [0.0; 8];
        self.store(&mut target, 0);
        target
    }

    fn from_array(array: Self::Array) -> Self {
        Self::load(&array, 0)
    }

    type ComplexArray = [Complex<f32>; 4];

    fn to_complex_array(self) -> Self::ComplexArray {
        unsafe { mem::transmute(self.to_array()) }
    }

    fn from_complex_array(array: Self::ComplexArray) -> Self {
        Self::from_array(unsafe { mem::transmute(array) })
    }

    fn array_to_regs(array: &[f32]) -> &[Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &[Self] = mem::transmute(array);
            &trans[0 .. len / reg_len]
        }
   }

    fn array_to_regs_mut(array: &mut [f32]) -> &mut [Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &mut [Self] = mem::transmute(array);
            &mut trans[0 .. len / reg_len]
        }
    }

    fn len() -> usize {
        8
    }

    fn load(array: &[f32], idx: usize) -> f32x8 {
        f32x8::load(array, idx)
    }

    fn load_wrap(array: &[f32], idx: usize) -> f32x8 {
        let mut temp = [0.0; 8];
        for i in 0..temp.len() {
            temp[i] = array[(idx + i) % array.len()];
        }
        f32x8::load(&temp, 0)
    }

    fn from_complex(value: Complex<f32>) -> f32x8 {
        f32x8::new(value.re, value.im, value.re, value.im,
                   value.re, value.im, value.re, value.im)
    }

    fn add_real(self, value: f32) -> f32x8
    {
        let increment = f32x8::splat(value);
        self + increment
    }

    fn add_complex(self, value: Complex<f32>) -> f32x8
    {
        let increment = f32x8::from_complex(value);
        self + increment
    }

    fn scale_real(self, value: f32) -> f32x8
    {
        let scale_vector = f32x8::splat(value);
        self * scale_vector
    }

    fn scale_complex(self, value: Complex<f32>) -> f32x8
    {
        let scaling_real = f32x8::splat(value.re);
        let scaling_imag = f32x8::splat(value.im);
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f32x8::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2),
                                  self.extract(5), self.extract(4), self.extract(7), self.extract(6));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn mul_complex(self, value: f32x8) -> f32x8
    {
        let scaling_real = f32x8::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2),
                                      value.extract(4), value.extract(4), value.extract(6), value.extract(6));
        let scaling_imag = f32x8::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3),
                                      value.extract(5), value.extract(5), value.extract(7), value.extract(7));
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f32x8::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2),
                                  self.extract(5), self.extract(4), self.extract(7), self.extract(6));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn div_complex(self, value: f32x8) -> f32x8
    {
                let scaling_imag = f32x8::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2),
                                      self.extract(4), self.extract(4), self.extract(6), self.extract(6));
                let scaling_real = f32x8::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3),
                                      self.extract(5), self.extract(5), self.extract(7), self.extract(7));
                let parallel = scaling_real * value;
                // There should be a shufps operation which shuffles the vector self
                let shuffled = f32x8::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2),
                                  value.extract(5), value.extract(4), value.extract(7), value.extract(6));
                let cross = scaling_imag * shuffled;
                let mul = parallel.addsub(cross);
                let square = shuffled * shuffled;
                let square_shuffled = f32x8::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2),
                                         square.extract(5), square.extract(4), square.extract(7), square.extract(6));
                let sum = square + square_shuffled;
                let div = mul / sum;
                f32x8::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2),
                   div.extract(5), div.extract(4), div.extract(7), div.extract(6))
    }

    fn complex_abs_squared(self) -> f32x8
    {
        let squared = self * self;
        squared.hadd(squared)
    }

    fn complex_abs(self) -> f32x8
    {
        let squared_sum = self.complex_abs_squared();
        AvxF32x8::sqrt(squared_sum)
    }

    fn complex_abs_squared2(self) -> f32x8
    {
        let abs = self.complex_abs_squared();
        f32x4::new(
            abs.extract(0), abs.extract(4), abs.extract(1), abs.extract(5),
            abs.extract(2), abs.extract(6), abs.extract(3), abs.extract(7))
    }

    fn complex_abs2(self) -> f32x8
    {
        let abs = self.complex_abs();
        f32x4::new(
            abs.extract(0), abs.extract(4), abs.extract(1), abs.extract(5),
            abs.extract(2), abs.extract(6), abs.extract(3), abs.extract(7))
    }

    fn sqrt(self) -> f32x8 {
        AvxF32x8::sqrt(self)
    }

    fn store(self, target: &mut [f32], index: usize)
    {
        self.store(target, index);
    }

    fn store_half(self, target: &mut [f32], index: usize)
    {
        let mut temp = [0.0; 8];
        self.store(&mut temp, 0);
        target[index] = temp[0];
        target[index + 1] = temp[1];
        target[index + 2] = temp[4];
        target[index + 3] = temp[5];
    }

    fn sum_real(&self) -> f32 {
        self.extract(0) +
        self.extract(1) +
        self.extract(2) +
        self.extract(3) +
        self.extract(4) +
        self.extract(5) +
        self.extract(6) +
        self.extract(7)
    }

    fn sum_complex(&self) -> Complex<f32> {
        Complex::<f32>::new(self.extract(0) + self.extract(2) + self.extract(4) + self.extract(6),
                            self.extract(1) + self.extract(3) + self.extract(5) + self.extract(7))
    }
}

impl Simd<f64> for f64x4
{
    type Array = [f64; 4];

    fn to_array(self) -> Self::Array {
        let mut target = [0.0; 4];
        self.store(&mut target, 0);
        target
    }

    fn from_array(array: Self::Array) -> Self {
        Self::load(&array, 0)
    }

    type ComplexArray = [Complex<f64>; 2];

    fn to_complex_array(self) -> Self::ComplexArray {
        unsafe { mem::transmute(self.to_array()) }
    }

    fn from_complex_array(array: Self::ComplexArray) -> Self {
        Self::from_array(unsafe { mem::transmute(array) })
    }

    fn array_to_regs(array: &[f64]) -> &[Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &[Self] = mem::transmute(array);
            &trans[0 .. len / reg_len]
        }
    }

    fn array_to_regs_mut(array: &mut [f64]) -> &mut [Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &mut [Self] = mem::transmute(array);
            &mut trans[0 .. len / reg_len]
        }
    }

    fn len() -> usize {
        4
    }

    fn load(array: &[f64], idx: usize) -> f64x4 {
        f64x4::load(array, idx)
    }

    fn load_wrap(array: &[f64], idx: usize) -> f64x4 {
        let mut temp = [0.0; 4];
        for i in 0..temp.len() {
            temp[i] = array[(idx + i) % array.len()];
        }
        f64x4::load(&temp, 0)
    }

    fn from_complex(value: Complex<f64>) -> f64x4 {
        f64x4::new(value.re, value.im, value.re, value.im)
    }

    fn add_real(self, value: f64) -> f64x4
    {
        let increment = f64x4::splat(value);
        self + increment
    }

    fn add_complex(self, value: Complex<f64>) -> f64x4
    {
        let increment = f64x4::new(value.re, value.im, value.re, value.im);
        self + increment
    }

    fn scale_real(self, value: f64) -> f64x4
    {
        let scale_vector = f64x4::splat(value);
        self * scale_vector
    }

    fn scale_complex(self, value: Complex<f64>) -> f64x4
    {
        let scaling_real = f64x4::splat(value.re);
        let scaling_imag = f64x4::splat(value.im);
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn mul_complex(self, value: f64x4) -> f64x4
    {
        let scaling_real = f64x4::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2));
        let scaling_imag = f64x4::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3));
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn div_complex(self, value: f64x4) -> f64x4
    {
        let scaling_imag = f64x4::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2));
        let scaling_real = f64x4::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3));
        let parallel = scaling_real * value;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2));
        let cross = scaling_imag * shuffled;
        let mul = parallel.addsub(cross);
        let square = shuffled * shuffled;
        let square_shuffled = f64x4::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2));
        let sum = square + square_shuffled;
        let div = mul / sum;
        f64x4::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2))
    }

    fn complex_abs_squared(self) -> f64x4
    {
        let squared = self * self;
        squared.hadd(squared)
    }

    fn complex_abs(self) -> f64x4
    {
        let squared_sum = self.complex_abs_squared();
        AvxF64x4::sqrt(squared_sum)
    }

    fn complex_abs_squared2(self) -> f64x4
    {
        let abs = self.complex_abs_squared();
        f32x4::new(abs.extract(0), abs.extract(2), abs.extract(1), abs.extract(3))
    }

    fn complex_abs2(self) -> f64x4
    {
        let abs = self.complex_abs();
        f32x4::new(abs.extract(0), abs.extract(2), abs.extract(1), abs.extract(3))
    }

    fn sqrt(self) -> f64x4 {
        f64x4::new(self.extract(0).sqrt(), self.extract(1).sqrt(), self.extract(2).sqrt(), self.extract(3).sqrt())
    }

    fn store(self, target: &mut [f64], index: usize)
    {
        self.store(target, index);
    }

    fn store_half(self, target: &mut [f64], index: usize)
    {
        let mut temp = [0.0; 4];
        self.store(&mut temp, 0);
        target[index] = temp[0];
        target[index + 1] = temp[2];
    }

    fn sum_real(&self) -> f64 {
        self.extract(0) +
        self.extract(1) +
        self.extract(2) +
        self.extract(3)
    }

    fn sum_complex(&self) -> Complex<f64> {
        Complex::<f64>::new(self.extract(0) + self.extract(2), self.extract(1) + self.extract(3))
    }
}
<commit_msg>Tested recent changes to AVX<commit_after>use num::complex::Complex;
use super::Simd;
use simd::x86::avx::{f32x8,f64x4,AvxF32x8,AvxF64x4};
use std::mem;

pub type Reg32 = f32x8;

pub type Reg64 = f64x4;

impl Simd<f32> for f32x8
{
    type Array = [f32; 8];

    fn to_array(self) -> Self::Array {
        let mut target = [0.0; 8];
        self.store(&mut target, 0);
        target
    }

    fn from_array(array: Self::Array) -> Self {
        Self::load(&array, 0)
    }

    type ComplexArray = [Complex<f32>; 4];

    fn to_complex_array(self) -> Self::ComplexArray {
        unsafe { mem::transmute(self.to_array()) }
    }

    fn from_complex_array(array: Self::ComplexArray) -> Self {
        Self::from_array(unsafe { mem::transmute(array) })
    }

    fn array_to_regs(array: &[f32]) -> &[Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &[Self] = mem::transmute(array);
            &trans[0 .. len / reg_len]
        }
   }

    fn array_to_regs_mut(array: &mut [f32]) -> &mut [Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &mut [Self] = mem::transmute(array);
            &mut trans[0 .. len / reg_len]
        }
    }

    fn len() -> usize {
        8
    }

    fn load(array: &[f32], idx: usize) -> f32x8 {
        f32x8::load(array, idx)
    }

    fn load_wrap(array: &[f32], idx: usize) -> f32x8 {
        let mut temp = [0.0; 8];
        for i in 0..temp.len() {
            temp[i] = array[(idx + i) % array.len()];
        }
        f32x8::load(&temp, 0)
    }

    fn from_complex(value: Complex<f32>) -> f32x8 {
        f32x8::new(value.re, value.im, value.re, value.im,
                   value.re, value.im, value.re, value.im)
    }

    fn add_real(self, value: f32) -> f32x8
    {
        let increment = f32x8::splat(value);
        self + increment
    }

    fn add_complex(self, value: Complex<f32>) -> f32x8
    {
        let increment = f32x8::from_complex(value);
        self + increment
    }

    fn scale_real(self, value: f32) -> f32x8
    {
        let scale_vector = f32x8::splat(value);
        self * scale_vector
    }

    fn scale_complex(self, value: Complex<f32>) -> f32x8
    {
        let scaling_real = f32x8::splat(value.re);
        let scaling_imag = f32x8::splat(value.im);
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f32x8::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2),
                                  self.extract(5), self.extract(4), self.extract(7), self.extract(6));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn mul_complex(self, value: f32x8) -> f32x8
    {
        let scaling_real = f32x8::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2),
                                      value.extract(4), value.extract(4), value.extract(6), value.extract(6));
        let scaling_imag = f32x8::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3),
                                      value.extract(5), value.extract(5), value.extract(7), value.extract(7));
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f32x8::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2),
                                  self.extract(5), self.extract(4), self.extract(7), self.extract(6));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn div_complex(self, value: f32x8) -> f32x8
    {
                let scaling_imag = f32x8::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2),
                                      self.extract(4), self.extract(4), self.extract(6), self.extract(6));
                let scaling_real = f32x8::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3),
                                      self.extract(5), self.extract(5), self.extract(7), self.extract(7));
                let parallel = scaling_real * value;
                // There should be a shufps operation which shuffles the vector self
                let shuffled = f32x8::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2),
                                  value.extract(5), value.extract(4), value.extract(7), value.extract(6));
                let cross = scaling_imag * shuffled;
                let mul = parallel.addsub(cross);
                let square = shuffled * shuffled;
                let square_shuffled = f32x8::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2),
                                         square.extract(5), square.extract(4), square.extract(7), square.extract(6));
                let sum = square + square_shuffled;
                let div = mul / sum;
                f32x8::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2),
                   div.extract(5), div.extract(4), div.extract(7), div.extract(6))
    }

    fn complex_abs_squared(self) -> f32x8
    {
        let squared = self * self;
        squared.hadd(squared)
    }

    fn complex_abs(self) -> f32x8
    {
        let squared_sum = self.complex_abs_squared();
        AvxF32x8::sqrt(squared_sum)
    }

    fn complex_abs_squared2(self) -> f32x8
    {
        let abs = self.complex_abs_squared();
        f32x8::new(
            abs.extract(0), abs.extract(4), abs.extract(1), abs.extract(5),
            abs.extract(2), abs.extract(6), abs.extract(3), abs.extract(7))
    }

    fn complex_abs2(self) -> f32x8
    {
        let abs = self.complex_abs();
        f32x8::new(
            abs.extract(0), abs.extract(4), abs.extract(1), abs.extract(5),
            abs.extract(2), abs.extract(6), abs.extract(3), abs.extract(7))
    }

    fn sqrt(self) -> f32x8 {
        AvxF32x8::sqrt(self)
    }

    fn store(self, target: &mut [f32], index: usize)
    {
        self.store(target, index);
    }

    fn store_half(self, target: &mut [f32], index: usize)
    {
        let mut temp = [0.0; 8];
        self.store(&mut temp, 0);
        target[index] = temp[0];
        target[index + 1] = temp[1];
        target[index + 2] = temp[4];
        target[index + 3] = temp[5];
    }

    fn sum_real(&self) -> f32 {
        self.extract(0) +
        self.extract(1) +
        self.extract(2) +
        self.extract(3) +
        self.extract(4) +
        self.extract(5) +
        self.extract(6) +
        self.extract(7)
    }

    fn sum_complex(&self) -> Complex<f32> {
        Complex::<f32>::new(self.extract(0) + self.extract(2) + self.extract(4) + self.extract(6),
                            self.extract(1) + self.extract(3) + self.extract(5) + self.extract(7))
    }
}

impl Simd<f64> for f64x4
{
    type Array = [f64; 4];

    fn to_array(self) -> Self::Array {
        let mut target = [0.0; 4];
        self.store(&mut target, 0);
        target
    }

    fn from_array(array: Self::Array) -> Self {
        Self::load(&array, 0)
    }

    type ComplexArray = [Complex<f64>; 2];

    fn to_complex_array(self) -> Self::ComplexArray {
        unsafe { mem::transmute(self.to_array()) }
    }

    fn from_complex_array(array: Self::ComplexArray) -> Self {
        Self::from_array(unsafe { mem::transmute(array) })
    }

    fn array_to_regs(array: &[f64]) -> &[Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &[Self] = mem::transmute(array);
            &trans[0 .. len / reg_len]
        }
    }

    fn array_to_regs_mut(array: &mut [f64]) -> &mut [Self] {
        unsafe {
            let len = array.len();
            let reg_len = Self::len();
            if len % reg_len != 0 {
                panic!("Argument must be dividable by {}", reg_len);
            }
            let trans: &mut [Self] = mem::transmute(array);
            &mut trans[0 .. len / reg_len]
        }
    }

    fn len() -> usize {
        4
    }

    fn load(array: &[f64], idx: usize) -> f64x4 {
        f64x4::load(array, idx)
    }

    fn load_wrap(array: &[f64], idx: usize) -> f64x4 {
        let mut temp = [0.0; 4];
        for i in 0..temp.len() {
            temp[i] = array[(idx + i) % array.len()];
        }
        f64x4::load(&temp, 0)
    }

    fn from_complex(value: Complex<f64>) -> f64x4 {
        f64x4::new(value.re, value.im, value.re, value.im)
    }

    fn add_real(self, value: f64) -> f64x4
    {
        let increment = f64x4::splat(value);
        self + increment
    }

    fn add_complex(self, value: Complex<f64>) -> f64x4
    {
        let increment = f64x4::new(value.re, value.im, value.re, value.im);
        self + increment
    }

    fn scale_real(self, value: f64) -> f64x4
    {
        let scale_vector = f64x4::splat(value);
        self * scale_vector
    }

    fn scale_complex(self, value: Complex<f64>) -> f64x4
    {
        let scaling_real = f64x4::splat(value.re);
        let scaling_imag = f64x4::splat(value.im);
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn mul_complex(self, value: f64x4) -> f64x4
    {
        let scaling_real = f64x4::new(value.extract(0), value.extract(0), value.extract(2), value.extract(2));
        let scaling_imag = f64x4::new(value.extract(1), value.extract(1), value.extract(3), value.extract(3));
        let parallel = scaling_real * self;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(self.extract(1), self.extract(0), self.extract(3), self.extract(2));
        let cross = scaling_imag * shuffled;
        parallel.addsub(cross)
    }

    fn div_complex(self, value: f64x4) -> f64x4
    {
        let scaling_imag = f64x4::new(self.extract(0), self.extract(0), self.extract(2), self.extract(2));
        let scaling_real = f64x4::new(self.extract(1), self.extract(1), self.extract(3), self.extract(3));
        let parallel = scaling_real * value;
        // There should be a shufps operation which shuffles the vector self
        let shuffled = f64x4::new(value.extract(1), value.extract(0), value.extract(3), value.extract(2));
        let cross = scaling_imag * shuffled;
        let mul = parallel.addsub(cross);
        let square = shuffled * shuffled;
        let square_shuffled = f64x4::new(square.extract(1), square.extract(0), square.extract(3), square.extract(2));
        let sum = square + square_shuffled;
        let div = mul / sum;
        f64x4::new(div.extract(1), div.extract(0), div.extract(3), div.extract(2))
    }

    fn complex_abs_squared(self) -> f64x4
    {
        let squared = self * self;
        squared.hadd(squared)
    }

    fn complex_abs(self) -> f64x4
    {
        let squared_sum = self.complex_abs_squared();
        AvxF64x4::sqrt(squared_sum)
    }

    fn complex_abs_squared2(self) -> f64x4
    {
        let abs = self.complex_abs_squared();
        f64x4::new(abs.extract(0), abs.extract(2), abs.extract(1), abs.extract(3))
    }

    fn complex_abs2(self) -> f64x4
    {
        let abs = self.complex_abs();
        f64x4::new(abs.extract(0), abs.extract(2), abs.extract(1), abs.extract(3))
    }

    fn sqrt(self) -> f64x4 {
        f64x4::new(self.extract(0).sqrt(), self.extract(1).sqrt(), self.extract(2).sqrt(), self.extract(3).sqrt())
    }

    fn store(self, target: &mut [f64], index: usize)
    {
        self.store(target, index);
    }

    fn store_half(self, target: &mut [f64], index: usize)
    {
        let mut temp = [0.0; 4];
        self.store(&mut temp, 0);
        target[index] = temp[0];
        target[index + 1] = temp[2];
    }

    fn sum_real(&self) -> f64 {
        self.extract(0) +
        self.extract(1) +
        self.extract(2) +
        self.extract(3)
    }

    fn sum_complex(&self) -> Complex<f64> {
        Complex::<f64>::new(self.extract(0) + self.extract(2), self.extract(1) + self.extract(3))
    }
}
<|endoftext|>