<commit_before>use std::ops::Add;
use ndarray;

type TileArray = ndarray::Array2<Tile>;
// Index into a TileArray; arrays are indexed in (row (y), column (x)) order
type TileIndex = (usize, usize);

impl Add<Direction> for TileIndex {
    type Output = TileIndex;

    fn add(self, direction: Direction) -> TileIndex {
        let (y, x) = self;
        match direction {
            Direction::Up => (y - 1, x),
            Direction::Down => (y + 1, x),
            Direction::Left => (y, x - 1),
            Direction::Right => (y, x + 1),
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

pub struct GameState {
    tiles: TileArray,
    snake_head: TileIndex,
    snake_tail: TileIndex,
    snake_dir: Direction,
}

impl GameState {
    pub fn new() -> Self {
        let width = 80;
        let height = 50;
        let mut tiles = ndarray::Array::from_elem((height, width), Tile::Floor);

        // Build level wall
        for x in 0..width {
            tiles[(0, x)] = Tile::Wall;
            tiles[(height - 1, x)] = Tile::Wall;
        }
        for y in 0..height {
            tiles[(y, 0)] = Tile::Wall;
            tiles[(y, width - 1)] = Tile::Wall;
        }

        // Place snake
        tiles[(3, 3)] = Tile::Snake(Direction::Right);
        tiles[(3, 4)] = Tile::Snake(Direction::Right);
        tiles[(3, 5)] = Tile::Snake(Direction::Right);
        let snake_head = (3, 5);
        let snake_tail = (3, 3);
        let snake_dir = Direction::Right;

        Self {
            tiles: tiles,
            snake_head: snake_head,
            snake_tail: snake_tail,
            snake_dir: snake_dir,
        }
    }

    pub fn tiles(&self) -> &TileArray {
        &self.tiles
    }

    pub fn set_snake_dir(&mut self, new_snake_dir: Direction) {
        self.snake_dir = new_snake_dir;
    }

    pub fn update(&mut self) {
        // Move snake
        let new_snake_head = self.snake_head + self.snake_dir;
        // Handle collision
        match self.tiles[new_snake_head] {
            Tile::Wall | Tile::Snake(_) => {
                // New head collides with wall or snake, so game over
                // FIXME Implement game over, just return for now
                return;
            }
            Tile::Food => {
                // New head collides with food, so eat the food
                // FIXME Spawn new food; adjust score
            }
            Tile::Floor => (), // No collision
        }
        self.tiles[self.snake_head] = Tile::Snake(self.snake_dir);
        self.tiles[new_snake_head] = Tile::Snake(self.snake_dir);
        self.snake_head = new_snake_head;
        if let Tile::Snake(snake_tail_dir) = self.tiles[self.snake_tail] {
            self.tiles[self.snake_tail] = Tile::Floor;
            self.snake_tail = self.snake_tail + snake_tail_dir;
        } else {
            panic!("Expected Snake(_) on tile at position {:?}, found {:?} instead",
                   self.snake_tail,
                   self.tiles[self.snake_tail]);
        }
    }
}

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

#[derive(Copy, Clone, Debug)]
pub enum Tile {
    Floor,
    Wall,
    Food,
    // A Snake tile contains the direction that part of the snake is moving in (pointing towards
    // the head of the snake)
    Snake(Direction),
}
<commit_msg>Spawn and eat food!<commit_after>use std::ops::Add;
use ndarray;
use rand;
use rand::Rng;

type TileArray = ndarray::Array2<Tile>;
// Index into a TileArray; arrays are indexed in (row (y), column (x)) order
type TileIndex = (usize, usize);

impl Add<Direction> for TileIndex {
    type Output = TileIndex;

    fn add(self, direction: Direction) -> TileIndex {
        let (y, x) = self;
        match direction {
            Direction::Up => (y - 1, x),
            Direction::Down => (y + 1, x),
            Direction::Left => (y, x - 1),
            Direction::Right => (y, x + 1),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

pub struct GameState {
    tiles: TileArray,
    snake_head: TileIndex,
    snake_tail: TileIndex,
    snake_dir: Direction,
}

impl GameState {
    pub fn new() -> Self {
        let width = 80;
        let height = 50;
        let mut tiles = ndarray::Array::from_elem((height, width), Tile::Floor);

        // Build level wall
        for x in 0..width {
            tiles[(0, x)] = Tile::Wall;
            tiles[(height - 1, x)] = Tile::Wall;
        }
        for y in 0..height {
            tiles[(y, 0)] = Tile::Wall;
            tiles[(y, width - 1)] = Tile::Wall;
        }

        // Place snake
        tiles[(3, 3)] = Tile::Snake(Direction::Right);
        tiles[(3, 4)] = Tile::Snake(Direction::Right);
        tiles[(3, 5)] = Tile::Snake(Direction::Right);
        let snake_head = (3, 5);
        let snake_tail = (3, 3);
        let snake_dir = Direction::Right;

        let mut game_state = Self {
            tiles: tiles,
            snake_head: snake_head,
            snake_tail: snake_tail,
            snake_dir: snake_dir,
        };
        game_state.spawn_food();

        game_state
    }

    fn spawn_food(&mut self) {
        let (height, width) = self.tiles.dim();
        let mut rng = rand::thread_rng();
        let mut index = (0, 0);
        // FIXME This will hang if the snake fills the entire playing field
        loop {
            index.0 = rng.gen_range(1, height - 1);
            index.1 = rng.gen_range(1, width - 1);
            if self.tiles[index] == Tile::Floor {
                break;
            };
        }
        self.tiles[index] = Tile::Food;
    }

    pub fn tiles(&self) -> &TileArray {
        &self.tiles
    }

    pub fn set_snake_dir(&mut self, new_snake_dir: Direction) {
        self.snake_dir = new_snake_dir;
    }

    pub fn update(&mut self) {
        // Move snake
        let new_snake_head = self.snake_head + self.snake_dir;
        let mut eat_food = false;
        // Handle collision
        match self.tiles[new_snake_head] {
            Tile::Wall | Tile::Snake(_) => {
                // New head collides with wall or snake, so game over
                // FIXME Implement game over, just return for now
                return;
            }
            Tile::Food => {
                // New head collides with food, so eat the food
                eat_food = true;
            }
            Tile::Floor => {} // No collision
        }
        self.tiles[self.snake_head] = Tile::Snake(self.snake_dir);
        self.tiles[new_snake_head] = Tile::Snake(self.snake_dir);
        self.snake_head = new_snake_head;
        if eat_food {
            // FIXME Adjust score
            self.spawn_food();
        } else if let Tile::Snake(snake_tail_dir) = self.tiles[self.snake_tail] {
            self.tiles[self.snake_tail] = Tile::Floor;
            self.snake_tail = self.snake_tail + snake_tail_dir;
        } else {
            panic!("Expected Snake(_) on tile at position {:?}, found {:?} instead",
                   self.snake_tail,
                   self.tiles[self.snake_tail]);
        }
    }
}

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

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Tile {
    Floor,
    Wall,
    Food,
    // A Snake tile contains the direction that part of the snake is moving in (pointing towards
    // the head of the snake)
    Snake(Direction),
}
<|endoftext|>


<commit_before>
use map::Map;
use player::Player;
use room::Room;

pub struct Game<'a> {
	player: Player,
	map: &'a Map,
	current_room: &'a Room
}

impl<'a> Game<'a> {
	pub fn new(player: Player, map: &'a Map) -> Game<'a> {
		Game{player: player, map: map, current_room: map.get_start_room()}
	}

	pub fn start(&mut self) {
		println!("Game Started");
		println!("You've entered \"{}\"", self.current_room.get_title());
		println!("{}", self.current_room.get_first_description());
	}
}
<commit_msg>I added a simple user input capturing loop<commit_after>
use map::Map;
use player::Player;
use room::Room;
use std::io;

pub struct Game<'a> {
	player: Player,
	map: &'a Map,
	current_room: &'a Room
}

impl<'a> Game<'a> {
	pub fn new(player: Player, map: &'a Map) -> Game<'a> {
		Game{player: player, map: map, current_room: map.get_start_room()}
	}

	pub fn start(&mut self) {
		println!("Game Started");

		loop {
			println!("You've entered \"{}\"", self.current_room.get_title());
			println!("{}", self.current_room.get_first_description());
			println!("What would you like to do?");

			let mut action = String::new();
			io::stdin().read_line(&mut action).expect("Failed to read action!");
		}
	}
}
<|endoftext|>


<commit_before>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH, ZOPFLI_WINDOW_SIZE};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct HashThing {
    head: [i32; 65536],  /* Hash value to index of its most recent occurrence. */
    prev: Vec<u16>,  /* Index to index of prev. occurrence of same hash. */
    hashval: [i32; ZOPFLI_WINDOW_SIZE],  /* Index to hash value at this index. */
    val: i32,  /* Current hash value. */
}

impl HashThing {
    fn new() -> HashThing {
        HashThing {
            head: [-1; 65536],
            prev: (0..ZOPFLI_WINDOW_SIZE as u16).collect(),
            hashval: [-1; ZOPFLI_WINDOW_SIZE],
            val: 0,
        }
    }

    fn reset(&mut self) {
        self.val = 0;
        self.head = [-1; 65536];
        self.prev = (0..ZOPFLI_WINDOW_SIZE as u16).collect();
        self.hashval = [-1; ZOPFLI_WINDOW_SIZE];
    }

    fn update(&mut self, hpos: usize) {
        self.hashval[hpos] = self.val;

        let index = self.val as usize;
        let head_index = self.head[index];
        self.prev[hpos] = if head_index != -1 && self.hashval[head_index as usize] == self.val {
            head_index as u16
        } else {
            hpos as u16
        };
        self.head[index] = hpos as i32;
    }
}

pub struct ZopfliHash {
    hash1: HashThing,
    hash2: HashThing,
    pub same: [u16; ZOPFLI_WINDOW_SIZE],  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new() -> ZopfliHash {
        ZopfliHash {
            hash1: HashThing::new(),
            hash2: HashThing::new(),
            same: [0; ZOPFLI_WINDOW_SIZE],
        }
    }

    pub fn reset(&mut self) {
        self.hash1.reset();
        self.hash2.reset();
        self.same = [0; ZOPFLI_WINDOW_SIZE];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.hash1.val = ((self.hash1.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;

        self.hash1.update(hpos);

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        let same = self.same[same_index];
        if same > 1 {
            amount = same - 1;
        }

        self.same[hpos] = amount;

        self.hash2.val = ((amount.wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.hash1.val as u16) as i32;

        self.hash2.update(hpos);
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.head[index],
            Which::Hash2 => self.hash2.head[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.hash1.prev[index],
            Which::Hash2 => self.hash2.prev[index],
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.hashval[index],
            Which::Hash2 => self.hash2.hashval[index],
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.val,
            Which::Hash2 => self.hash2.val,
        }
    }
}
<commit_msg>Try to get rid of an array indexing in hash?<commit_after>use util::{ZOPFLI_WINDOW_MASK, ZOPFLI_MIN_MATCH, ZOPFLI_WINDOW_SIZE};

const HASH_SHIFT: i32 = 5;
const HASH_MASK: i32 = 32767;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Which {
    Hash1,
    Hash2,
}

pub struct SmallerHashThing {
    prev: u16, /* Index to index of prev. occurrence of same hash. */
    hashval: i32, /* Index to hash value at this index. */
}

pub struct HashThing {
    head: [i32; 65536],  /* Hash value to index of its most recent occurrence. */
    prev_and_hashval: Vec<SmallerHashThing>,
    val: i32,  /* Current hash value. */
}

impl HashThing {
    fn new() -> HashThing {
        HashThing {
            head: [-1; 65536],
            prev_and_hashval: (0..ZOPFLI_WINDOW_SIZE as u16).map(|p| {
                SmallerHashThing {
                    prev: p,
                    hashval: -1,
                }
            }).collect(),
            val: 0,
        }
    }

    fn reset(&mut self) {
        self.val = 0;
        self.head = [-1; 65536];
        self.prev_and_hashval = (0..ZOPFLI_WINDOW_SIZE as u16).map(|p| {
            SmallerHashThing {
                prev: p,
                hashval: -1,
            }
        }).collect();
    }

    fn update(&mut self, hpos: usize) {
        let hashval = self.val;
        let index = self.val as usize;
        let head_index = self.head[index];
        let prev = if head_index != -1 && self.prev_and_hashval[head_index as usize].hashval == self.val {
            head_index as u16
        } else {
            hpos as u16
        };

        self.prev_and_hashval[hpos] = SmallerHashThing {
            prev: prev,
            hashval: hashval,
        };
        self.head[index] = hpos as i32;
    }
}

pub struct ZopfliHash {
    hash1: HashThing,
    hash2: HashThing,
    pub same: [u16; ZOPFLI_WINDOW_SIZE],  /* Amount of repetitions of same byte after this .*/
}

impl ZopfliHash {
    pub fn new() -> ZopfliHash {
        ZopfliHash {
            hash1: HashThing::new(),
            hash2: HashThing::new(),
            same: [0; ZOPFLI_WINDOW_SIZE],
        }
    }

    pub fn reset(&mut self) {
        self.hash1.reset();
        self.hash2.reset();
        self.same = [0; ZOPFLI_WINDOW_SIZE];
    }

    pub fn warmup(&mut self, arr: &[u8], pos: usize, end: usize) {
        let c = arr[pos];
        self.update_val(c);

        if pos + 1 < end {
            let c = arr[pos + 1];
            self.update_val(c);
        }
    }

    /// Update the sliding hash value with the given byte. All calls to this function
    /// must be made on consecutive input characters. Since the hash value exists out
    /// of multiple input bytes, a few warmups with this function are needed initially.
    fn update_val(&mut self, c: u8) {
        self.hash1.val = ((self.hash1.val << HASH_SHIFT) ^ c as i32) & HASH_MASK;
    }

    pub fn update(&mut self, array: &[u8], pos: usize) {
        let hash_value = array.get(pos + ZOPFLI_MIN_MATCH - 1).cloned().unwrap_or(0);
        self.update_val(hash_value);

        let hpos = pos & ZOPFLI_WINDOW_MASK;

        self.hash1.update(hpos);

        // Update "same".
        let mut amount = 0;
        let same_index = pos.wrapping_sub(1) & ZOPFLI_WINDOW_MASK;
        let same = self.same[same_index];
        if same > 1 {
            amount = same - 1;
        }

        self.same[hpos] = amount;

        self.hash2.val = ((amount.wrapping_sub(ZOPFLI_MIN_MATCH as u16) & 255) ^ self.hash1.val as u16) as i32;

        self.hash2.update(hpos);
    }

    pub fn head_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.head[index],
            Which::Hash2 => self.hash2.head[index],
        }
    }

    pub fn prev_at(&self, index: usize, which: Which) -> u16 {
        match which {
            Which::Hash1 => self.hash1.prev_and_hashval[index].prev,
            Which::Hash2 => self.hash2.prev_and_hashval[index].prev,
        }
    }

    pub fn hash_val_at(&self, index: usize, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.prev_and_hashval[index].hashval,
            Which::Hash2 => self.hash2.prev_and_hashval[index].hashval,
        }
    }

    pub fn val(&self, which: Which) -> i32 {
        match which {
            Which::Hash1 => self.hash1.val,
            Which::Hash2 => self.hash2.val,
        }
    }
}
<|endoftext|>


<commit_before>use todo::Todo;
use std::fs::File;
use storage::StorageError;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TodoList {
    pub name: String,
    pub list: Vec<Todo>,
}

impl TodoList {
    pub fn new(name: &str) -> TodoList {
        TodoList {
            name: name.to_string(),
            list: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tdo {
    pub lists: Vec<TodoList>,
}

impl Tdo {
    pub fn new() -> Tdo {
        Tdo { lists: Vec::new() }
    }

    pub fn load(path: &str) -> Tdo {
        let file = File::open(path).unwrap();
        super::serde_json::from_reader(&file).unwrap()
    }

    pub fn save(&self, path: &str) -> Result<(), StorageError> {
        match File::create(path) {
            Ok(mut f) => {
                let _ = super::serde_json::to_writer_pretty(&mut f, self);
                Ok(())
            },
            Err(_) => Err(StorageError::FileCorrupted)
        }

    }
}
<commit_msg>make self in load mutable<commit_after>use todo::Todo;
use std::fs::File;
use storage::StorageError;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TodoList {
    pub name: String,
    pub list: Vec<Todo>,
}

impl TodoList {
    pub fn new(name: &str) -> TodoList {
        TodoList {
            name: name.to_string(),
            list: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tdo {
    pub lists: Vec<TodoList>,
}

impl Tdo {
    pub fn new() -> Tdo {
        Tdo { lists: Vec::new() }
    }

    pub fn load(&mut self, path: &str) {
        let file = File::open(path).unwrap();
        let json: Tdo = super::serde_json::from_reader(&file).unwrap();
        self.lists = json.lists;
    }

    pub fn save(&self, path: &str) -> Result<(), StorageError> {
        match File::create(path) {
            Ok(mut f) => {
                let _ = super::serde_json::to_writer_pretty(&mut f, self);
                Ok(())
            },
            Err(_) => Err(StorageError::FileCorrupted)
        }

    }
}
<|endoftext|>


<commit_before>use std::io::{Write, BufWriter};
use std::fs::File;
mod vector;
use vector::Vec3;

fn main() {
  let nx = 300;
  let ny = 200;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  for j in (0..ny).rev() {
    for i in 0..nx {
      let color = Vec3 { i: i as f64 / nx as f64, j: j as f64 / ny as f64, k: 0.5 };

      let ir = (255.99*color.i) as i32;
      let ig = (255.99*color.j) as i32;
      let ib = (255.99*color.k) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Update vector use with new syntax<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;
mod vector;
use vector::Vec3;

fn main() {
  let nx = 300;
  let ny = 200;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  for j in (0..ny).rev() {
    for i in 0..nx {
      let color = Vec3::new(i as f64 / nx as f64, j as f64 / ny as f64, 0.5);

      let ir = (255.99*color.i) as i32;
      let ig = (255.99*color.j) as i32;
      let ib = (255.99*color.k) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>


<commit_before>#![deny(warnings, clippy::pedantic)]
#![allow(
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::too_many_lines,
    clippy::wildcard_imports
)]

#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::agents::{Expiring, ImportKeySet, KeySet};
use crate::config::{ConfigBuilder, ConfigRc};
use crate::crypto::SigningAlgorithm;
use crate::utils::{
    pem::{self, ParsedKeyPair},
    BoxError,
};
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use log::info;
use serde::Deserialize;
use std::{
    io::{Cursor, Read},
    net::SocketAddr,
    path::{Path, PathBuf},
    time::SystemTime,
};

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker [CONFIG] --import-key FILE
  portier-broker --version
  portier-broker --help

Options:
  --version          Print version information and exit
  --help             Print this help message and exit
  --import-key FILE  Import a PEM private key, for migrating to rotating keys
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<PathBuf>,
    flag_import_key: Option<PathBuf>,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    crate::utils::logger::init();

    // We spawn a bunch of background tasks on the Tokio executor. If these panic, we want to exit
    // instead of continuing on without the task.
    let next_panic_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |info| {
        next_panic_hook(info);
        std::process::exit(1);
    }));

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();

    if let Some(ref path) = args.flag_import_key {
        import_key(builder, path).await;
    } else {
        start_server(builder).await;
    }
}

async fn start_server(builder: ConfigBuilder) {
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!("failed to build configuration: {}", err)),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    builder.serve(make_service).await.expect("Server error");
}

async fn import_key(builder: ConfigBuilder, file: &Path) {
    let contents = if file == Path::new("-") {
        let mut buf = Vec::new();
        if let Err(err) = std::io::stdin().read_to_end(&mut buf) {
            panic!("Could not read key from stdin: {}", err)
        }
        buf
    } else {
        match std::fs::read(file) {
            Ok(contents) => contents,
            Err(err) => panic!("Could not open key file '{}': {}", file.display(), err),
        }
    };

    let contents = match String::from_utf8(contents) {
        Ok(contents) => contents,
        Err(err) => panic!("Key file '{}' is not valid UTF-8: {}", file.display(), err),
    };

    let key = match pem::parse_key_pairs(Cursor::new(contents.as_bytes())) {
        Ok(keys) if keys.len() == 1 => keys.into_iter().next().unwrap(),
        Ok(_) => panic!(
            "Expected exactly one PEM block in key file '{}'",
            file.display()
        ),
        Err(err) => panic!(
            "Could not parse PEM in key file '{}': {}",
            file.display(),
            err
        ),
    };

    let keys_ttl = builder.keys_ttl;
    let store = builder
        .into_store()
        .await
        .unwrap_or_else(|err| panic!("failed to build configuration: {}", err));

    let signing_alg = match key {
        ParsedKeyPair::Ed25519(_) => SigningAlgorithm::EdDsa,
        ParsedKeyPair::Rsa(_) => SigningAlgorithm::Rs256,
    };
    store
        .send(ImportKeySet(KeySet {
            signing_alg,
            current: Some(Expiring {
                value: contents,
                expires: SystemTime::now() + keys_ttl,
            }),
            next: None,
            previous: None,
        }))
        .await;
    eprintln!("Successfully imported {} key", signing_alg);

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}
<commit_msg>Remove deny(warnings)<commit_after>#![warn(clippy::pedantic)]
#![allow(
    clippy::cast_possible_truncation,
    clippy::cast_possible_wrap,
    clippy::cast_sign_loss,
    clippy::enum_glob_use,
    clippy::module_name_repetitions,
    clippy::single_match_else,
    clippy::too_many_lines,
    clippy::wildcard_imports
)]

#[macro_use]
mod macros;

mod agents;
mod bridges;
mod config;
mod crypto;
mod email_address;
mod error;
mod handlers;
mod router;
mod utils;
mod validation;
mod web;
mod webfinger;

use crate::agents::{Expiring, ImportKeySet, KeySet};
use crate::config::{ConfigBuilder, ConfigRc};
use crate::crypto::SigningAlgorithm;
use crate::utils::{
    pem::{self, ParsedKeyPair},
    BoxError,
};
use crate::web::Service;
use futures_util::future;
use hyper::{server::Server, service::make_service_fn};
use log::info;
use serde::Deserialize;
use std::{
    io::{Cursor, Read},
    net::SocketAddr,
    path::{Path, PathBuf},
    time::SystemTime,
};

/// Defines the program's version, as set by Cargo at compile time.
const VERSION: &str = env!("CARGO_PKG_VERSION");

/// Defines the program's usage string.
///
/// [Docopt](http://docopt.org) parses this and generates a custom argv parser.
const USAGE: &str = r#"
Portier Broker

Usage:
  portier-broker [CONFIG]
  portier-broker [CONFIG] --import-key FILE
  portier-broker --version
  portier-broker --help

Options:
  --version          Print version information and exit
  --help             Print this help message and exit
  --import-key FILE  Import a PEM private key, for migrating to rotating keys
"#;

/// Holds parsed command line parameters.
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct Args {
    arg_CONFIG: Option<PathBuf>,
    flag_import_key: Option<PathBuf>,
}

/// The `main()` method. Will loop forever to serve HTTP requests.
#[tokio::main]
async fn main() {
    crate::utils::logger::init();

    // We spawn a bunch of background tasks on the Tokio executor. If these panic, we want to exit
    // instead of continuing on without the task.
    let next_panic_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |info| {
        next_panic_hook(info);
        std::process::exit(1);
    }));

    let args: Args = docopt::Docopt::new(USAGE)
        .map(|docopt| docopt.version(Some(VERSION.to_owned())))
        .and_then(|docopt| docopt.deserialize())
        .unwrap_or_else(|e| e.exit());

    let mut builder = ConfigBuilder::new();
    if let Some(ref path) = args.arg_CONFIG {
        builder.update_from_file(path);
    }
    builder.update_from_common_env();
    builder.update_from_broker_env();

    if let Some(ref path) = args.flag_import_key {
        import_key(builder, path).await;
    } else {
        start_server(builder).await;
    }
}

async fn start_server(builder: ConfigBuilder) {
    let app = ConfigRc::new(
        builder
            .done()
            .await
            .unwrap_or_else(|err| panic!("failed to build configuration: {}", err)),
    );

    // TODO: Add unix socket support.
    let builder = match listenfd::ListenFd::from_env().take_tcp_listener(0) {
        Ok(Some(tcp_listener)) => {
            let builder = Server::from_tcp(tcp_listener).expect("Socket activation failed");
            info!("Listening on the socket received from the service manager");
            builder
        }
        Ok(None) => {
            let ip_addr = app
                .listen_ip
                .parse()
                .expect("Unable to parse listen address");
            let addr = SocketAddr::new(ip_addr, app.listen_port);
            let builder = Server::bind(&addr);
            info!("Listening on {}", addr);
            builder
        }
        Err(err) => {
            panic!("Socket activation failed: {}", err);
        }
    };

    #[cfg(unix)]
    sd_notify::notify(true, &[sd_notify::NotifyState::Ready])
        .expect("Failed to signal ready to the service manager");

    let make_service = make_service_fn(|stream| {
        let app = ConfigRc::clone(&app);
        future::ok::<_, BoxError>(Service::new(app, stream))
    });
    builder.serve(make_service).await.expect("Server error");
}

async fn import_key(builder: ConfigBuilder, file: &Path) {
    let contents = if file == Path::new("-") {
        let mut buf = Vec::new();
        if let Err(err) = std::io::stdin().read_to_end(&mut buf) {
            panic!("Could not read key from stdin: {}", err)
        }
        buf
    } else {
        match std::fs::read(file) {
            Ok(contents) => contents,
            Err(err) => panic!("Could not open key file '{}': {}", file.display(), err),
        }
    };

    let contents = match String::from_utf8(contents) {
        Ok(contents) => contents,
        Err(err) => panic!("Key file '{}' is not valid UTF-8: {}", file.display(), err),
    };

    let key = match pem::parse_key_pairs(Cursor::new(contents.as_bytes())) {
        Ok(keys) if keys.len() == 1 => keys.into_iter().next().unwrap(),
        Ok(_) => panic!(
            "Expected exactly one PEM block in key file '{}'",
            file.display()
        ),
        Err(err) => panic!(
            "Could not parse PEM in key file '{}': {}",
            file.display(),
            err
        ),
    };

    let keys_ttl = builder.keys_ttl;
    let store = builder
        .into_store()
        .await
        .unwrap_or_else(|err| panic!("failed to build configuration: {}", err));

    let signing_alg = match key {
        ParsedKeyPair::Ed25519(_) => SigningAlgorithm::EdDsa,
        ParsedKeyPair::Rsa(_) => SigningAlgorithm::Rs256,
    };
    store
        .send(ImportKeySet(KeySet {
            signing_alg,
            current: Some(Expiring {
                value: contents,
                expires: SystemTime::now() + keys_ttl,
            }),
            next: None,
            previous: None,
        }))
        .await;
    eprintln!("Successfully imported {} key", signing_alg);

    // TODO: This is a little hacky, but we don't have code to shutdown gracefully.
    // (Currently, if a Redis store is simply dropped, the pubsub task panics.)
    std::process::exit(0);
}
<|endoftext|>


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

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
    let mut state = state;
    let mut bytes = Vec::from_elem(k, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    let rows = 16 - k;

    loop {
        copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
        copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                state[row][i] = S[state[row][i - 1] as uint] ^ state[row - 1][i];
            }

            // Next t value.
            state[row + 1][0] = state[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
            copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    state[row - 1][col] = S[state[row][col - 1] as uint] ^ state[row][col];
                }
            }

            state[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
    let rows = 16 - k;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
        }

        // Last bytes are equal.
        values[row][32] = values[row][16];
        values[row][48] = values[row][16];

        // Next t value.
        values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            values[row][32 - col - 1] = S2[(values[row][32 - col] ^ values[row - 1][32 - col]) as uint];
            values[row][48 - col - 1] = S2[(values[row][48 - col] ^ values[row - 1][48 - col]) as uint];
        }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    // Iterate bytes starting from the end.
    for i in range(0, len).rev() {
        if num[i] == 255 {
            continue;
        }

        // Increase.
        num[i] += 1;

        // Set all bytes right of the current index to zero.
        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    // Increasing any further would overflow.
    false
}

fn check_collision(collision: &Collision) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let mut hashes = collision.iter().map(|msg| {
        md2_compress(&empty, msg.as_slice())
    });

    hashes.all(|md2| {
        first_hash.map_or_else(|| {
            first_hash = Some(md2);
            true
        }, |v| v == md2)
    })
}

fn main() {
    let k = 2;
    let state = create_initial_state(k);
    let collisions = find_collisions(state, k);

    // Check that the colliding messages we found generate the same hashes.
    if !collisions.iter().all(check_collision) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<commit_msg>simplify increase()<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(state: [[u8, ..49], ..19], k: uint) -> Collisions {
    let mut state = state;
    let mut bytes = Vec::from_elem(k, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    let rows = 16 - k;

    loop {
        copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
        copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                state[row][i] = S[state[row][i - 1] as uint] ^ state[row - 1][i];
            }

            // Next t value.
            state[row + 1][0] = state[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| state[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(state[rows].slice_mut(17, 17 + k), bytes.as_slice());
            copy_memory(state[rows].slice_mut(17 + 16, 17 + k + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(1, rows + 1).rev() {
                for col in range(17, 32 - row + 2) {
                    state[row - 1][col] = S[state[row][col - 1] as uint] ^ state[row][col];
                }
            }

            state[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(k: uint) -> [[u8, ..49], ..19] {
    let rows = 16 - k;
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
        // Fill row of T1.
        for i in range(1, 17) {
            values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
        }

        // Last bytes are equal.
        values[row][32] = values[row][16];
        values[row][48] = values[row][16];

        // Next t value.
        values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
        for row in range(2 + col, rows + 1).rev() {
            values[row][32 - col - 1] = S2[(values[row][32 - col] ^ values[row - 1][32 - col]) as uint];
            values[row][48 - col - 1] = S2[(values[row][48 - col] ^ values[row - 1][48 - col]) as uint];
        }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    // Iterate bytes starting from the end.
    range(0, num.len()).rev().any(|i| {
        if num[i] == 255 {
            return false;
        }

        // Increase.
        num[i] += 1;

        // Set all bytes right of the current index to zero.
        for i in range(i + 1, num.len()) {
            num[i] = 0;
        }

        true
    })
}

fn check_collision(collision: &Collision) -> bool {
    let empty = [0u8, ..16];
    let mut first_hash: Option<[u8, ..16]> = None;
    let mut hashes = collision.iter().map(|msg| {
        md2_compress(&empty, msg.as_slice())
    });

    hashes.all(|md2| {
        first_hash.map_or_else(|| {
            first_hash = Some(md2);
            true
        }, |v| v == md2)
    })
}

fn main() {
    let k = 2;
    let state = create_initial_state(k);
    let collisions = find_collisions(state, k);

    // Check that the colliding messages we found generate the same hashes.
    if !collisions.iter().all(check_collision) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate toml;
extern crate iron;
extern crate router;
extern crate core;

//use iron::Iron;
use iron::prelude::*;
use iron::headers::*;
use iron::{status, headers};

use core::str::Str;

use router::{Router};

struct SbWikiServer {
    listenaddr: String,
    wikipath: String,
    wikifrontpage: String,
}

impl SbWikiServer {
    //TODO: pass config object instead of bunch of argument
    pub fn new(listenaddr: String, wikipath: String,
           wikifrontpage: String) -> SbWikiServer {
        SbWikiServer {
            listenaddr: listenaddr,
            wikipath: wikipath,
            wikifrontpage: wikifrontpage,
        }
    }

    pub fn open(&self, isTLS: bool) {
        let mut wikidocument = self.wikipath.clone();
        wikidocument.push_str("/*");

        let mut router = Router::new();
        //TODO: fetch it from toml config.

        router.get(self.wikipath.as_slice(),
                   |req: &mut Request| self.wikiredirect(req));

        router.get(wikidocument.as_slice(),
                   |req: &mut Request| self.wikihandler(req));

        router.get("/",
                   |req: &mut Request| self.roothandler(req));
        router.get("/:query",
                        |req: &mut Request| self.roothandler(req));

        //let mut iron = Iron::new(router);
        //iron.http(self.listenaddr).unwrap();

        //self.iron = iron;

        Iron::new(router).http(
            self.listenaddr.clone().as_slice().as_slice()).unwrap();
    }

    fn roothandler(&self, req: &mut Request)
                   -> IronResult<Response> {
        let ref query = req.extensions.get::<Router>()
            .unwrap().find("query").unwrap_or("/");

        Ok(Response::with((status::Ok, *query)))
    }

    fn wikiredirect(&self, req: &mut Request)
                    -> IronResult<Response> {
        let mut url = req.url.path.clone();
        let mut header = Headers::new();
        let mut newpath = String::new();

        //TODO: customizable root page.
        url.push(self.wikifrontpage);

        for i in url.iter() {
            newpath.push_str("/");
            newpath.push_str(i);
        }

        println!("{}", newpath);
        header.set(Location(newpath));

        let mut resp: Response = Response::with((status::MovedPermanently));
        resp.headers = header;

        Ok(resp)
    }

    fn wikihandler(&self, req: &mut Request)
                   -> IronResult<Response> {
        let ref requrl = req.url.clone();
        let mut urlpath = requrl.path.clone();

        for i in urlpath.iter() {
            println!("{}\n", i);
        }

        Ok(Response::with((status::Ok, "Watch console.")))
    }
}

fn main() {
    let sbwiki: SbWikiServer = SbWikiServer::new(
        String::from_str("localhost:3000"),
        String::from_str("/wiki"),
        String::from_str("FrontPage"));

    sbwiki.open(false);
}
<commit_msg>Tries to fix lifetime. Still broken build.<commit_after>#![feature(collections)]

extern crate toml;
extern crate iron;
extern crate router;
extern crate core;

//use iron::Iron;
use iron::prelude::*;
use iron::headers::*;
use iron::{status, headers};

//use core::str::Str;

use router::{Router};

struct SbWikiServer<'sbwikisrv> {
    listenaddr: String,
    wikipath: String,
    wikifrontpage: String,
}

impl SbWikiServer {
    //TODO: pass config object instead of bunch of argument
    pub fn new(listenaddr: String, wikipath: String,
           wikifrontpage: String) -> SbWikiServer {
        SbWikiServer {
            listenaddr: listenaddr,
            wikipath: wikipath,
            wikifrontpage: wikifrontpage,
        }
    }

    pub fn open(&'sbwikisrv self, isTLS: bool) {
        let mut wikidocument = self.wikipath.clone();
        wikidocument.push_str("/*");

        let mut router = Router::new();
        //TODO: fetch it from toml config.

        router.get(self.wikipath.as_str(),
                   |req: &mut Request| -> IronResult<Response>
                   {self.wikiredirect(req)});

        router.get(wikidocument.as_str(),
                   |req: &mut Request| -> IronResult<Response>
                   {self.wikihandler(req)});

        router.get("/",
                   |req: &mut Request| -> IronResult<Response>
                   {self.roothandler(req)});/*
        router.get("/:query",
                        |req: &mut Request| &self.roothandler(req));
        */
        //let mut iron = Iron::new(router);
        //iron.http(self.listenaddr).unwrap();

        //self.iron = iron;

        Iron::new(router).http(
            self.listenaddr.clone().as_str()).unwrap();
    }

    fn roothandler(&self, req: &mut Request)
                   -> IronResult<Response> {
        let ref query = req.extensions.get::<Router>()
            .unwrap().find("query").unwrap_or("/");

        Ok(Response::with((status::Ok, *query)))
    }

    fn wikiredirect(&self, req: &mut Request)
                    -> IronResult<Response> {
        let mut url = req.url.path.clone();
        let mut header = Headers::new();
        let mut newpath = String::new();

        //TODO: customizable root page.
        url.push(self.wikifrontpage);

        for i in url.iter() {
            newpath.push_str("/");
            newpath.push_str(i);
        }

        println!("{}", newpath);
        header.set(Location(newpath));

        let mut resp: Response = Response::with((status::MovedPermanently));
        resp.headers = header;

        Ok(resp)
    }

    fn wikihandler(&self, req: &mut Request)
                   -> IronResult<Response> {
        let ref requrl = req.url.clone();
        let mut urlpath = requrl.path.clone();

        for i in urlpath.iter() {
            println!("{}\n", i);
        }

        Ok(Response::with((status::Ok, "Watch console.")))
    }
}

fn main() {
    let sbwiki: SbWikiServer = SbWikiServer::new(
        String::from_str("localhost:3000"),
        String::from_str("/wiki"),
        String::from_str("FrontPage"));

    sbwiki.open(false);
}
<|endoftext|>


<commit_before>// extern crate rand;
extern crate clap;
extern crate image;

use std::path::Path;
// use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .arg(Arg::with_name("input")
            .short("i")
            .long("input")
            .value_name("PATH")
            .help("path to input file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("PATH")
            .help("path to output file")
            .takes_value(true)
            .required(true))
        /*.arg(Arg::with_name("v")
            .short("v")
            .multiple(true)
            .help("Sets the level of verbosity"))*/
        .get_matches();

    let input = matches.value_of("input").unwrap();
    let output = matches.value_of("output").unwrap();

    handle_request(input, output);

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    // match matches.occurrences_of("v") {
    // 0 => println!("No verbose info"),
    // 1 => println!("Some verbose info"),
    // 2 => println!("Tons of verbose info"),
    // 3 | _ => println!("Don't be crazy"),
    // }

}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions {:?}", in_img.dimensions());
    println!("{:?}", in_img.color());

    let ref mut out_img = RgbaImage::new(in_img.width(), in_img.height());

    sort_them_pixels(in_img, out_img);

    let _ = out_img.save(output).unwrap();
}

fn sort_them_pixels(input: &DynamicImage, output: &mut RgbaImage) {
    let mut x = 0;
    let mut y = 0;

    let mut tmp = Vec::new();

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > 10 {
            tmp.sort_by(|a, b| (a[3]).cmp(&b[1]));
            while !tmp.is_empty() {
                output.put_pixel(x, y, tmp.pop().unwrap());
                y = y + (x + 1) / input.width();
                x = (x + 1) % input.width();
            }
        }
    }
}
<commit_msg>moved output image into sorting function<commit_after>// extern crate rand;
extern crate clap;
extern crate image;

use std::path::Path;
// use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

fn main() {
    let matches = App::new("asami")
        .version("0.1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .arg(Arg::with_name("input")
            .short("i")
            .long("input")
            .value_name("PATH")
            .help("path to input file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("PATH")
            .help("path to output file")
            .takes_value(true)
            .required(true))
        .get_matches();

    let input = matches.value_of("input").unwrap();
    let output = matches.value_of("output").unwrap();

    handle_request(input, output);
}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    println!("dimensions {:?}", in_img.dimensions());
    println!("{:?}", in_img.color());

    let out_img = sort_them_pixels(in_img);

    let _ = out_img.save(output).unwrap();
}

fn sort_them_pixels(input: &DynamicImage) -> RgbaImage {
    let mut output = RgbaImage::new(input.width(), input.height());

    let mut x = 0;
    let mut y = 0;

    let mut tmp = Vec::new();

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > 100 {
            tmp.sort_by(|a, b| (a[3]).cmp(&b[1]));
            while !tmp.is_empty() {
                output.put_pixel(x, y, tmp.pop().unwrap());
                y = y + (x + 1) / input.width();
                x = (x + 1) % input.width();
            }
        }
    }
    output
}
<|endoftext|>


<commit_before>//extern crate rand;
extern crate clap;
extern crate image;

//use std::io;
//use std::cmp::Ordering;
//use std::fs::File;
use std::path::Path;
//use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

/*fn foo() {

    let secret_number = rand::thread_rng().gen_range(1, 101);

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("failed to read line");

    let guess: i32 = guess.trim().parse()
        .expect("please type a number");

    match guess.cmp(&secret_number) {
        Ordering::Equal => println!("same"),
        Ordering::Greater => println!("too big"),
        Ordering::Less => println!("too small"),
    }
}*/

fn main() {
    let matches = App::new("asami")
        //.version("1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .arg(Arg::with_name("input")
            .short("i")
            .long("input")
            .value_name("PATH")
            .help("path to input file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("PATH")
            .help("path to output file")
            .takes_value(true)
            .required(true))
        /*.arg(Arg::with_name("v")
            .short("v")
            .multiple(true)
            .help("Sets the level of verbosity"))*/
        .get_matches();

    let input = matches.value_of("input").unwrap();
    let output = matches.value_of("output").unwrap();

    handle_request(input, output);

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    /*match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }*/
}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    // The dimensions method returns the images width and height
    println!("dimensions {:?}", in_img.dimensions());

    // The color method returns the image's ColorType
    println!("{:?}", in_img.color());

    let ref mut out_img = RgbaImage::new(in_img.width(), in_img.height());

    sort_them_pixels(in_img, out_img);

    // Write the contents of this image to the Writer in PNG format.
    let _ = out_img.save(output).unwrap();
}

fn sort_them_pixels(input: &DynamicImage, output: &mut RgbaImage){
    let mut tmp_x = 0;
    let mut tmp_y = 0;

    let mut tmp = Vec::new();

    for (x, y, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > 20 {
            tmp.sort_by(|a, b| a[0].cmp(&b[0]));
            //tmp = Vec::new();
            while !tmp.is_empty() {
                output.put_pixel(tmp_x, tmp_y, tmp.pop().unwrap());
                tmp_y = tmp_y + (tmp_x + 1) / input.width();
                tmp_x = (tmp_x + 1) % input.width();
            }
        }
    }
}
<commit_msg>now based on green value<commit_after>//extern crate rand;
extern crate clap;
extern crate image;

//use std::io;
//use std::cmp::Ordering;
//use std::fs::File;
use std::path::Path;
//use rand::Rng;
use clap::{Arg, App};
use image::{DynamicImage, GenericImage, RgbaImage};

/*fn foo() {

    let secret_number = rand::thread_rng().gen_range(1, 101);

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("failed to read line");

    let guess: i32 = guess.trim().parse()
        .expect("please type a number");

    match guess.cmp(&secret_number) {
        Ordering::Equal => println!("same"),
        Ordering::Greater => println!("too big"),
        Ordering::Less => println!("too small"),
    }
}*/

fn main() {
    let matches = App::new("asami")
        //.version("1.0")
        .author("Sebastian Schulz <mail@sesc.me>")
        .about("pixel sorter")
        .arg(Arg::with_name("input")
            .short("i")
            .long("input")
            .value_name("PATH")
            .help("path to input file")
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .value_name("PATH")
            .help("path to output file")
            .takes_value(true)
            .required(true))
        /*.arg(Arg::with_name("v")
            .short("v")
            .multiple(true)
            .help("Sets the level of verbosity"))*/
        .get_matches();

    let input = matches.value_of("input").unwrap();
    let output = matches.value_of("output").unwrap();

    handle_request(input, output);

    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    /*match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }*/
}

fn handle_request(input: &str, output: &str) {
    println!("input: {}, output: {}", input, output);

    let ref in_img = image::open(&Path::new(input)).unwrap();

    // The dimensions method returns the images width and height
    println!("dimensions {:?}", in_img.dimensions());

    // The color method returns the image's ColorType
    println!("{:?}", in_img.color());

    let ref mut out_img = RgbaImage::new(in_img.width(), in_img.height());

    sort_them_pixels(in_img, out_img);

    // Write the contents of this image to the Writer in PNG format.
    let _ = out_img.save(output).unwrap();
}

fn sort_them_pixels(input: &DynamicImage, output: &mut RgbaImage){
    let mut x = 0;
    let mut y = 0;

    let mut tmp = Vec::new();

    for (_, _, pixel) in input.pixels() {
        tmp.push(pixel);
        if tmp.len() > 10 {
            tmp.sort_by(|a, b| (a[1]).cmp(&b[1]));
            //tmp = Vec::new();
            while !tmp.is_empty() {
                output.put_pixel(x, y, tmp.pop().unwrap());
                y = y + (x + 1) / input.width();
                x = (x + 1) % input.width();
            }
        }
    }
}
<|endoftext|>


<commit_before>// base💯 - Copyright 2017 Adam Niederer

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#![allow(non_upper_case_globals)]
#![cfg_attr(test, feature(test))]
#![cfg_attr(feature = "simd", feature(target_feature))]
#![cfg_attr(feature = "simd", feature(asm))]
#![cfg_attr(feature = "simd", feature(cfg_target_feature))]

#[macro_use] extern crate clap;
#[cfg(feature = "simd")] extern crate stdsimd;

use std::io::{self, Read, Write, BufRead, BufReader, BufWriter};
use std::fs::File;
use std::iter::Iterator;
use clap::App;

fn main() {
    let cli_spec = load_yaml!("cli.yml");
    let cli_args = App::from_yaml(cli_spec).get_matches();

    let mut reader = {
        if let Some(path) = cli_args.value_of("input") {
            Box::new(BufReader::new(match File::open(path) {
                Ok(path) => path,
                _ => {
                    writeln!(io::stderr(), "base💯: no such file: {}", path).expect("base💯: stderr write error");
                    return;
                }
            })) as Box<BufRead>
        } else {
            Box::new(BufReader::new(io::stdin())) as Box<BufRead>
        }
    };

    let mut writer = BufWriter::new(io::stdout());

    if cli_args.is_present("decode") {
        let mut write_buf = [0u8; 0x10000];
        let mut buffer = [0u8; 0x10000];

        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            match writer.write_all(&emoji_to_char(&buffer[..num_read], &mut write_buf)[..num_read / 4]) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    } else {
        let mut write_buf = [0u8; 0x40000];
        let mut buffer = [0u8; 0x10000];

        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            match writer.write_all(&char_to_emoji(&buffer[..num_read], &mut write_buf)[..num_read * 4]) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    }
    writer.flush().expect("Write error");
}

#[cfg(any(not(feature = "simd"), not(target_arch = "x86_64")))]
fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    for (i, chunk) in buf.chunks(4).enumerate() {
        out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55)
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(target_feature = "avx2")]
pub fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    use stdsimd::simd::u8x32;
    use stdsimd::vendor::{_mm256_packus_epi32, _mm256_packus_epi16, _mm256_and_si256, _mm256_shuffle_pd};
    let mut i = 0;
    for chunk in buf.chunks(128) {
        if chunk.len() < 128 {
            // Non-SIMD implementation for the final <128 bytes
            for (i, chunk) in chunk.chunks(4).enumerate() {
                out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55)
            }
        } else {
            // AVX implementation of decoding algo
            // a, b, c, d contain one garbage word and one useful word
            let a_dirty = u8x32::load(chunk, i);
            let b_dirty = u8x32::load(chunk, i + 32);
            let c_dirty = u8x32::load(chunk, i + 64);
            let d_dirty = u8x32::load(chunk, i + 96);
            let dirty_mask = u8x32::new(0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF,
                                        0x00, 0x00, 0xFF, 0xFF);

            let hi_mask = u8x32::new(0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00);

            let lo_mask = u8x32::new(0x80, 0x00, 0x80, 0x02, 0x80, 0x04, 0x80, 0x06,
                                     0x80, 0x08, 0x80, 0x0A, 0x80, 0x0C, 0x80, 0x0E,
                                     0x80, 0x10, 0x80, 0x12, 0x80, 0x14, 0x80, 0x16,
                                     0x80, 0x18, 0x80, 0x1A, 0x80, 0x1C, 0x80, 0x1E);

            let hi: u8x32;
            let lo: u8x32;

            // x1 .. x4 now contain 0x00, 0x00, 0xhi, 0xlo ...
            // x1 and x2 now contain interleaved high and low bytes
            // x1 contains 0x00 0xhi, x2 0x00 0xlo, etc.
            // x1 now contains all the lo bytes, x2 has all the hi bytes
            unsafe {
                asm! {
                    "vpand x1, x1, xm
                     vpand x2, x2, xm
                     vpand x3, x3, xm
                     vpand x4, x4, xm

                     vpackusdw x1, x1, x2
                     vpackusdw x2, x3, x4

                     vpshufb x3, x2, xh
                     vpshufb x4, x2, xl
                     vpshufb x1, x1, xh
                     vpshufb x2, x1, xl

                     vpackuswb x1, x2, x4
                     vpackuswb x2, x1, x3

                     vpshufb x2, x1, xl"
                     : "={x1}"(lo), "={x2}"(hi)
                     : "{x1}"(a_dirty), "{x2}"(b_dirty), "{x3}"(c_dirty),
                       "{x4}"(d_dirty), "{xm}"(dirty_mask), "{xh}"(hi_mask)
                       "{xl}"(lo_mask)
                    : "cc"
                    : "intel"
                }
            }
            // Make a, b, c, d contain one 0x00 and one userful word

            // // Pack useful words of a, b, c, d
            // let a_interleaved = _mm256_packus_epi32(a_dirty_masked, b_dirty_masked).as_u8x32();
            // let b_interleaved = _mm256_packus_epi32(c_dirty_masked, d_dirty_masked).as_u8x32();

            // Shuffle bytes in words and zero out the high bit

            // let a_hi_masked = _mm256_and_si256(a_interleaved, hi_mask);
            // let b_hi_masked = _mm256_and_si256(b_interleaved, hi_mask);

            // unsafe {
            //     asm! {
            //         : "r" (a)
            //         : "%xmm15"

            //     }
            // }

            // let a_lo_masked = _mm256_shuffle_epi8(a_interleaved, lo_mask).as_i16x16();
            // let b_lo_masked = _mm256_shuffle_epi8(b_interleaved, lo_mask).as_i16x16();

            // All high bits
            // let hi = _mm256_packus_epi16(a_hi_masked, b_hi_masked);
            // // All low bits
            // let lo = _mm256_packus_epi16(a_lo_masked, b_lo_masked);

            ((((hi - u8x32::splat(143)) * u8x32::splat(64))
              + lo - u8x32::splat(128)) - u8x32::splat(55))
                .store(out, i);

            // TODO: Use Get rid of these scalar loads
            // let msbs = u8x32::new(chunk[2], chunk[6], chunk[10], chunk[14], chunk[18], chunk[22], chunk[26], chunk[30], chunk[34], chunk[38], chunk[42], chunk[46], chunk[50], chunk[54], chunk[58], chunk[62], chunk[66], chunk[70], chunk[74], chunk[78], chunk[82], chunk[86], chunk[90], chunk[94], chunk[98], chunk[102], chunk[106], chunk[110], chunk[114], chunk[118], chunk[122], chunk[126]);
            // let lsbs = u8x32::new(chunk[3], chunk[7], chunk[11], chunk[15], chunk[19], chunk[23], chunk[27], chunk[31], chunk[35], chunk[39], chunk[43], chunk[47], chunk[51], chunk[55], chunk[59], chunk[63], chunk[67], chunk[71], chunk[75], chunk[79], chunk[83], chunk[87], chunk[91], chunk[95], chunk[99], chunk[103], chunk[107], chunk[111], chunk[115], chunk[119], chunk[123], chunk[127]);
            // ((((msbs - u8x32::splat(143)) * u8x32::splat(64))
            //   + lsbs - u8x32::splat(128)) - u8x32::splat(55))
            //     .store(out, i);
            i += 128;
        }
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(all(not(target_feature = "avx2"), target_feature = "sse2"))]
pub fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    use stdsimd::simd::u8x16;
    let mut i = 0;
    for chunk in buf.chunks(64) {
        // Chunk data format: 0x00 0x00 0xhi 0xlo
        if chunk.len() < 64 {
            // Non-SIMD implementation for the final <128 bytes
            for (i, chunk) in chunk.chunks(4).enumerate() {
                out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55)
            }
        } else {

            // SSE2 implementation of decoding algo

            // TODO: Use Get rid of these scalar loads
            let msbs = u8x16::new(chunk[2], chunk[6], chunk[10], chunk[14], chunk[18], chunk[22], chunk[26], chunk[30], chunk[34], chunk[38], chunk[42], chunk[46], chunk[50], chunk[54], chunk[58], chunk[62]);
            let lsbs = u8x16::new(chunk[3], chunk[7], chunk[11], chunk[15], chunk[19], chunk[23], chunk[27], chunk[31], chunk[35], chunk[39], chunk[43], chunk[47], chunk[51], chunk[55], chunk[59], chunk[63]);
            ((((msbs - u8x16::splat(143)) * u8x16::splat(64))
              + lsbs - u8x16::splat(128)) - u8x16::splat(55))
                .store(out, i);
            i += 16;
        }
    }
    out
}

#[cfg(any(not(feature = "simd"), not(target_arch = "x86_64")))]
pub fn char_to_emoji<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b [u8] {
    for (i, ch) in buf.iter().enumerate() {
        out[4 * i + 0] = 0xf0;
        out[4 * i + 1] = 0x9f;
        out[4 * i + 2] = (((*ch as u16).wrapping_add(55)) / 64 + 143) as u8;
        out[4 * i + 3] = (ch.wrapping_add(55) % 64).wrapping_add(128);
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(target_feature = "sse2")]
pub fn char_to_emoji<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b [u8] {
    // TODO: SSE this up
    for (i, ch) in buf.iter().enumerate() {
        out[4 * i + 0] = 0xf0;
        out[4 * i + 1] = 0x9f;
        out[4 * i + 2] = (((*ch as u16).wrapping_add(55)) / 64 + 143) as u8;
        out[4 * i + 3] = (ch.wrapping_add(55) % 64).wrapping_add(128);
    }
    out
}
<commit_msg>AVX2 Vectorized Decoding<commit_after>// base💯 - Copyright 2017 Adam Niederer

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#![allow(non_upper_case_globals)]
#![cfg_attr(test, feature(test))]
#![cfg_attr(feature = "simd", feature(target_feature))]
#![cfg_attr(feature = "simd", feature(asm))]
#![cfg_attr(feature = "simd", feature(cfg_target_feature))]

#[macro_use] extern crate clap;
#[cfg(feature = "simd")] extern crate stdsimd;

use std::io::{self, Read, Write, BufRead, BufReader, BufWriter};
use std::fs::File;
use std::iter::Iterator;
use clap::App;

fn main() {
    let cli_spec = load_yaml!("cli.yml");
    let cli_args = App::from_yaml(cli_spec).get_matches();

    let mut reader = {
        if let Some(path) = cli_args.value_of("input") {
            Box::new(BufReader::new(match File::open(path) {
                Ok(path) => path,
                _ => {
                    writeln!(io::stderr(), "base💯: no such file: {}", path).expect("base💯: stderr write error");
                    return;
                }
            })) as Box<BufRead>
        } else {
            Box::new(BufReader::new(io::stdin())) as Box<BufRead>
        }
    };

    let mut writer = BufWriter::new(io::stdout());

    if cli_args.is_present("decode") {
        let mut write_buf = [0u8; 0x10000];
        let mut buffer = [0u8; 0x10000];

        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            match writer.write_all(&emoji_to_char(&buffer[..num_read], &mut write_buf)[..num_read / 4]) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    } else {
        let mut write_buf = [0u8; 0x40000];
        let mut buffer = [0u8; 0x10000];

        while let Ok(num_read) = reader.read(&mut buffer) {
            if num_read == 0 {
                break;
            }

            match writer.write_all(&char_to_emoji(&buffer[..num_read], &mut write_buf)[..num_read * 4]) {
                Ok(_) => (),
                _ => {
                    writeln!(io::stderr(), "base💯: write error").expect("base💯: stderr write error");
                    return;
                }
            }
        }
    }
    writer.flush().expect("Write error");
}

#[cfg(any(not(feature = "simd"), not(target_arch = "x86_64")))]
fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    for (i, chunk) in buf.chunks(4).enumerate() {
        out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55)
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(target_feature = "avx2")]
pub fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    use stdsimd::simd::u8x32;
    let mut i = 0;
    for chunk in buf.chunks(128) {
        if chunk.len() < 128 {
            // Non-SIMD implementation for the final <128 bytes
            for chunk in chunk.chunks(4) {
                out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55);
                i += 1;
            }
        } else {
            // AVX implementation of decoding algo
            // a, b, c, d contain one garbage word and one useful word
            let a = u8x32::load(chunk, 0);
            let b = u8x32::load(chunk, 32);
            let c = u8x32::load(chunk, 64);
            let d = u8x32::load(chunk, 96);

            // Constant mask for removing low bytes
            let hi_mask = u8x32::new(0xFF, 0x00, 0xFF, 0x00,0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,0xFF, 0x00, 0xFF, 0x00,
                                     0xFF, 0x00, 0xFF, 0x00,0xFF, 0x00, 0xFF, 0x00);

            // Results from the vector magic below
            let hi: u8x32;
            let lo: u8x32;

            unsafe {
                asm! {
                    "vpsrld ymm1, ymm1, 16
                     vpsrld ymm2, ymm2, 16
                     vpsrld ymm3, ymm3, 16
                     vpsrld ymm4, ymm4, 16
                     // ymm1 .. ymm4 now contain 0x00, 0x00, 0xhi, 0xlo ...

                     // Pack ymm* into ymm1 and ymm2 and order them properly
                     vpackusdw ymm1, ymm1, ymm2
                     vpackusdw ymm2, ymm3, ymm4
                     // vpackusdw interleaves ymm[13] and ymm[24; we want them end-to-end
                     vpermpd ymm1, ymm1, 0xD8 // [191:128] <-> [127:64]
                     vpermpd ymm2, ymm2, 0xD8 // [191:128] <-> [127:64]
                     // ymm1 and ymm2 now contain interleaved high and low bytes

                     // Store high bytes (0xhi 0x00) in ymm3 and ymm4
                     vpand ymm3, ymm1, ymm6
                     vpand ymm4, ymm2, ymm6
                     // Pack hi bytes into ymm4
                     vpackuswb ymm4, ymm3, ymm4

                     // Remove the high bytes and move low bytes into position
                     vpsrlw ymm1, ymm1, 8
                     vpsrlw ymm2, ymm2, 8
                     // Store low bytes in ymm3
                     vpackuswb ymm3, ymm1, ymm2

                     // Fight interleaving again
                     vpermpd ymm4, ymm4, 0xD8 // [191:128] <-> [127:64]
                     vpermpd ymm3, ymm3, 0xD8 // [191:128] <-> [127:64]"
                     : "={ymm3}"(lo), "={ymm4}"(hi)
                     : "{ymm1}"(a), "{ymm2}"(b), "{ymm3}"(c),
                       "{ymm4}"(d), "{ymm6}"(hi_mask)
                     : "cc"
                     : "intel"
                }
            }

            ((((hi - u8x32::splat(143)) * u8x32::splat(64))
              + lo - u8x32::splat(128)) - u8x32::splat(55))
                .store(out, i);
            i += 32;
        }
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(all(not(target_feature = "avx2"), target_feature = "sse2"))]
pub fn emoji_to_char<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b[u8] {
    use stdsimd::simd::u8x16;
    let mut i = 0;
    for chunk in buf.chunks(64) {
        // Chunk data format: 0x00 0x00 0xhi 0xlo
        if chunk.len() < 64 {
            // Non-SIMD implementation for the final <128 bytes
            for (i, chunk) in chunk.chunks(4).enumerate() {
                out[i] = ((chunk[2].wrapping_sub(143)).wrapping_mul(64)).wrapping_add(chunk[3].wrapping_sub(128)).wrapping_sub(55)
            }
        } else {

            // SSE2 implementation of decoding algo

            // TODO: Use Get rid of these scalar loads
            let msbs = u8x16::new(chunk[2], chunk[6], chunk[10], chunk[14], chunk[18], chunk[22], chunk[26], chunk[30], chunk[34], chunk[38], chunk[42], chunk[46], chunk[50], chunk[54], chunk[58], chunk[62]);
            let lsbs = u8x16::new(chunk[3], chunk[7], chunk[11], chunk[15], chunk[19], chunk[23], chunk[27], chunk[31], chunk[35], chunk[39], chunk[43], chunk[47], chunk[51], chunk[55], chunk[59], chunk[63]);
            ((((msbs - u8x16::splat(143)) * u8x16::splat(64))
              + lsbs - u8x16::splat(128)) - u8x16::splat(55))
                .store(out, i);
            i += 16;
        }
    }
    out
}

#[cfg(any(not(feature = "simd"), not(target_arch = "x86_64")))]
pub fn char_to_emoji<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b [u8] {
    for (i, ch) in buf.iter().enumerate() {
        out[4 * i + 0] = 0xf0;
        out[4 * i + 1] = 0x9f;
        out[4 * i + 2] = (((*ch as u16).wrapping_add(55)) / 64 + 143) as u8;
        out[4 * i + 3] = (ch.wrapping_add(55) % 64).wrapping_add(128);
    }
    out
}

#[cfg(feature = "simd")]
#[cfg(target_feature = "sse2")]
pub fn char_to_emoji<'a, 'b>(buf: &'a[u8], out: &'b mut [u8]) -> &'b [u8] {
    // TODO: SSE this up
    for (i, ch) in buf.iter().enumerate() {
        out[4 * i + 0] = 0xf0;
        out[4 * i + 1] = 0x9f;
        out[4 * i + 2] = (((*ch as u16).wrapping_add(55)) / 64 + 143) as u8;
        out[4 * i + 3] = (ch.wrapping_add(55) % 64).wrapping_add(128);
    }
    out
}
<|endoftext|>