<commit_before>// Copyright 2016 Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use ffi;
use {Error, DB};

use libc::{c_int, uint32_t};
use std::ffi::CString;
use std::path::Path;

pub struct BackupEngine {
    inner: *mut ffi::rocksdb_backup_engine_t,
}

pub struct BackupEngineOptions {
    inner: *mut ffi::rocksdb_options_t,
}

pub struct RestoreOptions {
    inner: *mut ffi::rocksdb_restore_options_t,
}

impl BackupEngine {
    /// Open a backup engine with the specified options.
    pub fn open<P: AsRef<Path>>(
        opts: &BackupEngineOptions,
        path: P,
    ) -> Result<BackupEngine, Error> {
        let path = path.as_ref();
        let cpath = match CString::new(path.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert path to CString \
                     when opening backup engine"
                        .to_owned(),
                ));
            }
        };

        let be: *mut ffi::rocksdb_backup_engine_t;
        unsafe { be = ffi_try!(ffi::rocksdb_backup_engine_open(opts.inner, cpath.as_ptr(),)) }

        if be.is_null() {
            return Err(Error::new("Could not initialize backup engine.".to_owned()));
        }

        Ok(BackupEngine { inner: be })
    }

    pub fn create_new_backup(&mut self, db: &DB) -> Result<(), Error> {
        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_create_new_backup(
                self.inner, db.inner,
            ));
            Ok(())
        }
    }

    pub fn purge_old_backups(&mut self, num_backups_to_keep: usize) -> Result<(), Error> {
        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_purge_old_backups(
                self.inner,
                num_backups_to_keep as uint32_t,
            ));
            Ok(())
        }
    }

    /// Restore from the latest backup
    ///
    /// # Arguments
    ///
    /// * `db_dir` - A path to the database directory
    /// * `wal_dir` - A path to the wal directory
    /// * `opts` - Restore options
    ///
    /// # Example
    ///
    /// ```ignore
    /// use rocksdb::backup::{BackupEngine, BackupEngineOptions};
    /// let backup_opts = BackupEngineOptions::default();
    /// let backup_engine = BackupEngine::open(&backup_opts, &backup_path).unwrap();
    /// let mut restore_option = rocksdb::backup::RestoreOptions::default();
    /// restore_option.set_keep_log_files(true); /// true to keep log files
    /// if let Err(e) = backup_engine.restore_from_latest_backup(&db_path, &wal_dir, &restore_option) {
    ///     error!("Failed to restore from the backup. Error:{:?}", e);
    ///     return Err(e.to_string());
    ///  }
    /// ```
    pub fn restore_from_latest_backup<D: AsRef<Path>,W: AsRef<Path>>(
        &mut self,
        db_dir: D,
        wal_dir: W,
        opts: &RestoreOptions,
    ) -> Result<(), Error> {
        let db_dir = db_dir.as_ref();
        let c_db_dir = match CString::new(db_dir.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert db_dir to CString \
                     when restoring from latest backup"
                        .to_owned(),
                ));
            }
        };

        let wal_dir = wal_dir.as_ref();
        let c_wal_dir = match CString::new(wal_dir.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert wal_dir to CString \
                     when restoring from latest backup"
                        .to_owned(),
                ));
            }
        };

        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_restore_db_from_latest_backup(
                self.inner,
                c_db_dir.as_ptr(),
                c_wal_dir.as_ptr(),
                opts.inner,
            ));
        }
        Ok(())
    }
}

impl BackupEngineOptions {
    //
}

impl RestoreOptions {
    pub fn set_keep_log_files(&mut self, keep_log_files: bool) {
        unsafe {
            ffi::rocksdb_restore_options_set_keep_log_files(self.inner, keep_log_files as c_int);
        }
    }
}

impl Default for BackupEngineOptions {
    fn default() -> BackupEngineOptions {
        unsafe {
            let opts = ffi::rocksdb_options_create();
            if opts.is_null() {
                panic!("Could not create RocksDB backup options".to_owned());
            }
            BackupEngineOptions { inner: opts }
        }
    }
}

impl Default for RestoreOptions {
    fn default() -> RestoreOptions {
        unsafe {
            let opts = ffi::rocksdb_restore_options_create();
            if opts.is_null() {
                panic!("Could not create RocksDB restore options".to_owned());
            }
            RestoreOptions { inner: opts }
        }
    }
}

impl Drop for BackupEngine {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_backup_engine_close(self.inner);
        }
    }
}

impl Drop for BackupEngineOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_options_destroy(self.inner);
        }
    }
}

impl Drop for RestoreOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_restore_options_destroy(self.inner);
        }
    }
}
<commit_msg>adding backup & restore test case<commit_after>// Copyright 2016 Alex Regueiro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use ffi;
use {Error, DB};

use libc::{c_int, uint32_t};
use std::ffi::CString;
use std::path::Path;

pub struct BackupEngine {
    inner: *mut ffi::rocksdb_backup_engine_t,
}

pub struct BackupEngineOptions {
    inner: *mut ffi::rocksdb_options_t,
}

pub struct RestoreOptions {
    inner: *mut ffi::rocksdb_restore_options_t,
}

impl BackupEngine {
    /// Open a backup engine with the specified options.
    pub fn open<P: AsRef<Path>>(
        opts: &BackupEngineOptions,
        path: P,
    ) -> Result<BackupEngine, Error> {
        let path = path.as_ref();
        let cpath = match CString::new(path.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert path to CString \
                     when opening backup engine"
                        .to_owned(),
                ));
            }
        };

        let be: *mut ffi::rocksdb_backup_engine_t;
        unsafe { be = ffi_try!(ffi::rocksdb_backup_engine_open(opts.inner, cpath.as_ptr(),)) }

        if be.is_null() {
            return Err(Error::new("Could not initialize backup engine.".to_owned()));
        }

        Ok(BackupEngine { inner: be })
    }

    pub fn create_new_backup(&mut self, db: &DB) -> Result<(), Error> {
        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_create_new_backup(
                self.inner, db.inner,
            ));
            Ok(())
        }
    }

    pub fn purge_old_backups(&mut self, num_backups_to_keep: usize) -> Result<(), Error> {
        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_purge_old_backups(
                self.inner,
                num_backups_to_keep as uint32_t,
            ));
            Ok(())
        }
    }

    /// Restore from the latest backup
    ///
    /// # Arguments
    ///
    /// * `db_dir` - A path to the database directory
    /// * `wal_dir` - A path to the wal directory
    /// * `opts` - Restore options
    ///
    /// # Example
    ///
    /// ```ignore
    /// use rocksdb::backup::{BackupEngine, BackupEngineOptions};
    /// let backup_opts = BackupEngineOptions::default();
    /// let mut backup_engine = BackupEngine::open(&backup_opts, &backup_path).unwrap();
    /// let mut restore_option = rocksdb::backup::RestoreOptions::default();
    /// restore_option.set_keep_log_files(true); /// true to keep log files
    /// if let Err(e) = backup_engine.restore_from_latest_backup(&db_path, &wal_dir, &restore_option) {
    ///     error!("Failed to restore from the backup. Error:{:?}", e);
    ///     return Err(e.to_string());
    ///  }
    /// ```
    pub fn restore_from_latest_backup<D: AsRef<Path>,W: AsRef<Path>>(
        &mut self,
        db_dir: D,
        wal_dir: W,
        opts: &RestoreOptions,
    ) -> Result<(), Error> {
        let db_dir = db_dir.as_ref();
        let c_db_dir = match CString::new(db_dir.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert db_dir to CString \
                     when restoring from latest backup"
                        .to_owned(),
                ));
            }
        };

        let wal_dir = wal_dir.as_ref();
        let c_wal_dir = match CString::new(wal_dir.to_string_lossy().as_bytes()) {
            Ok(c) => c,
            Err(_) => {
                return Err(Error::new(
                    "Failed to convert wal_dir to CString \
                     when restoring from latest backup"
                        .to_owned(),
                ));
            }
        };

        unsafe {
            ffi_try!(ffi::rocksdb_backup_engine_restore_db_from_latest_backup(
                self.inner,
                c_db_dir.as_ptr(),
                c_wal_dir.as_ptr(),
                opts.inner,
            ));
        }
        Ok(())
    }
}

impl BackupEngineOptions {
    //
}

impl RestoreOptions {
    pub fn set_keep_log_files(&mut self, keep_log_files: bool) {
        unsafe {
            ffi::rocksdb_restore_options_set_keep_log_files(self.inner, keep_log_files as c_int);
        }
    }
}

impl Default for BackupEngineOptions {
    fn default() -> BackupEngineOptions {
        unsafe {
            let opts = ffi::rocksdb_options_create();
            if opts.is_null() {
                panic!("Could not create RocksDB backup options".to_owned());
            }
            BackupEngineOptions { inner: opts }
        }
    }
}

impl Default for RestoreOptions {
    fn default() -> RestoreOptions {
        unsafe {
            let opts = ffi::rocksdb_restore_options_create();
            if opts.is_null() {
                panic!("Could not create RocksDB restore options".to_owned());
            }
            RestoreOptions { inner: opts }
        }
    }
}

impl Drop for BackupEngine {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_backup_engine_close(self.inner);
        }
    }
}

impl Drop for BackupEngineOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_options_destroy(self.inner);
        }
    }
}

impl Drop for RestoreOptions {
    fn drop(&mut self) {
        unsafe {
            ffi::rocksdb_restore_options_destroy(self.inner);
        }
    }
}

#[test]
fn backup_restore() {

    use db::DBVector;
    // create backup
    let path = "_rust_rocksdb_backup_restore_test";
    {
        let db = DB::open_default(path).unwrap();
        let p = db.put(b"k1", b"v1111");
        assert!(p.is_ok());
        let r: Result<Option<DBVector>, Error> = db.get(b"k1");
        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");

        let backup_path = "_rust_rocksdb_backup_path";
        {
            let backup_opts = BackupEngineOptions::default();
            let mut backup_engine = BackupEngine::open(&backup_opts, &backup_path).unwrap();

            let r = backup_engine.create_new_backup(&db);
            assert!(r.is_ok());

            let restore_path = "_rust_rocksdb_restore_from_backup_path";
            {
                let mut restore_option = RestoreOptions::default();
                restore_option.set_keep_log_files(true); // true to keep log files
                let restore_status = backup_engine.restore_from_latest_backup(&restore_path, &restore_path, &restore_option);
                assert!(restore_status.is_ok());

                let db = DB::open_default(restore_path).unwrap();

                let r: Result<Option<DBVector>, Error> = db.get(b"k1");
                assert!(r.unwrap().unwrap().to_utf8().unwrap() == "v1111");
            }
        }
    }

}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io;
use std::process::exit;
use std::io::Read;
use std::fs::File;
use std::iter;

use coreutils::extra::fail;

static MAN_PAGE: &'static str = r#"
    NAME
        wc - count words, bytes and lines of a file or byte stream.
    SYNOPSIS
        wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...
    DESCRIPTION
        This utility will dump word count, line count, and byte count of a file or byte stream. If multiple files are given, it will print a total count. If no file name is given, 'wc' reads from stdin until EOF.

        Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and count words) can be reduced to '-cw'.

        If no flags are given, 'wc' defaults to '-cwl'.
    OPTIONS
        -h
        --help
            Print this manual page.
        -c
        --bytes
            Count bytes.
        -w
        --words
            Count words (i.e. contiguous strings seperated by whitespaces).
        -l
        --lines
            Count lines (seperated by NL).
    AUTHOR
        This program was written mainly by Alice Maz.
"#;

#[derive(Copy, Clone)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags {
            count_lines: false,
            count_words: false,
            count_bytes: false,
        }
    }

    fn print_count<'a>(self, lines: u64, words: u64, bytes: u64, file: &'a str) {
        print!("    ");

        if self.count_lines {
            print!("{} ", lines);
        }
        if self.count_words {
            print!("{} ", words);
        }
        if self.count_bytes {
            print!("{} ", bytes);
        }

        print!("{}", file);

        println!("");
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::new();
    let mut first_file  = String::new();
    let mut args = env::args().skip(1);

    loop { // To avoid consumption of the iter, we use loop.
        let arg = if let Some(x) = args.next() { x } else { break };

        // TODO add -m, maybe add -L

        if arg.starts_with("--") {
            match &arg[2..] {
                "lines" => opts.count_lines = true,
                "words" => opts.count_words = true,
                "bytes" => opts.count_bytes = true,
                "help" => {
                    print!("{}", MAN_PAGE);
                    exit(0);
                },
                _ => fail(&format!("unknown flag, {}.", arg)),
            }
        } else if arg.starts_with("-") {
            for i in arg[1..].chars() {
                match i {
                    'l' => opts.count_lines = true,
                    'w' => opts.count_words = true,
                    'c' => opts.count_bytes = true,
                    'h' => {
                        print!("{}", MAN_PAGE);
                        exit(0);
                    }
                    _ => fail(&format!("unknown flag, {}.", i)),
                }
            }
        } else { // This is a file
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file == "" {
        let (lines, words, bytes) = do_count(io::stdin());
        opts.print_count(lines, words, bytes, "stdin");
    } else {
        let mut total_lines = 0;
        let mut total_words = 0;
        let mut total_bytes = 0;

        let single_file = args.len() == 1;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            match File::open(&path) {
                Ok(file) => {
                    let (lines, words, bytes) = do_count(file);

                    total_lines += lines;
                    total_words += words;
                    total_bytes += bytes;

                    opts.print_count(lines, words, bytes, &path);
                },
                Err(err) => fail(&format!("wc: cannot open file {}: {}", path, err)),
            }
        }

        if single_file {
            opts.print_count(total_lines, total_words, total_bytes, "total");
        }
    }
}

fn is_whitespace(byte: u8) -> bool {
    //FIXME this works like iswspace w/ default C locale
    //but not good enough for en_US.UTF8 among others

    byte == b'\n' // newline
    || byte == b'\t' // tab
    || byte == b'\r' // cr
    || byte == 0xc // formfeed
    || byte == 0xb // vtab
    || byte == b' ' // space
}

fn do_count<T: std::io::Read>(input: T) -> (u64, u64, u64) {
    let mut line_count = 0;
    let mut word_count = 0;
    let mut byte_count = 0;
    let mut got_space = true;

    for byte_result in input.bytes() {
        if let Ok(byte) = byte_result {
            if byte == b'\n' {
                line_count += 1;
            }

            if is_whitespace(byte) {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }
    }

    (line_count, word_count, byte_count)
}
<commit_msg>Performance improvements to wc<commit_after>#![deny(warnings)]

extern crate coreutils;

use std::env;
use std::io::{self, stdout, Write};
use std::io::Read;
use std::fs::File;
use std::iter;

use coreutils::extra::{OptionalExt, fail};

static MAN_PAGE: &'static str = r#"
    NAME
        wc - count words, bytes and lines of a file or byte stream.
    SYNOPSIS
        wc [-h | --help] [-c | --bytes] [-w | --words] [-l | --lines] [FILE 1] [FILE 2]...
    DESCRIPTION
        This utility will dump word count, line count, and byte count of a file or byte stream. If multiple files are given, it will print a total count. If no file name is given, 'wc' reads from stdin until EOF.

        Flags can be arbitrarily combined into a single flag, for example, '-c -w' (count bytes and count words) can be reduced to '-cw'.

        If no flags are given, 'wc' defaults to '-cwl'.
    OPTIONS
        -h
        --help
            Print this manual page.
        -c
        --bytes
            Count bytes.
        -w
        --words
            Count words (i.e. contiguous strings seperated by whitespaces).
        -l
        --lines
            Count lines (seperated by NL).
    AUTHOR
        This program was written mainly by Alice Maz.
"#;

#[derive(Copy, Clone)]
struct Flags {
    count_lines: bool,
    count_words: bool,
    count_bytes: bool,
}

impl Flags {
    fn new() -> Flags {
        Flags {
            count_lines: false,
            count_words: false,
            count_bytes: false,
        }
    }

    fn print_count<'a>(self, lines: u64, words: u64, bytes: u64, file: &'a str) {
        let mut stdout = stdout();
        stdout.write(b"    ").try();

        if self.count_lines {
            stdout.write(lines.to_string().as_bytes()).try();
            stdout.write(b" ").try();
        }
        if self.count_words {
            stdout.write(words.to_string().as_bytes()).try();
            stdout.write(b" ").try();
        }
        if self.count_bytes {
            stdout.write(bytes.to_string().as_bytes()).try();
            stdout.write(b" ").try();
        }

        stdout.write(file.as_bytes()).try();
        stdout.write(b"\n").try();
    }

    fn default_to(&mut self) {
        // Defaults to behavior of -lwc
        if !(self.count_lines || self.count_words || self.count_bytes) {
            self.count_lines = true;
            self.count_words = true;
            self.count_bytes = true;
        }
    }
}

fn main() {
    let mut opts = Flags::new();
    let mut first_file  = String::new();
    let mut args = env::args().skip(1);
    let mut stdout = stdout();

    loop { // To avoid consumption of the iter, we use loop.
        let arg = if let Some(x) = args.next() { x } else { break };

        // TODO add -m, maybe add -L

        if arg.starts_with("-") {
            match arg.as_str() {
                "--lines" | "-l" => opts.count_lines = true,
                "--words" | "-w" => opts.count_words = true,
                "--bytes" | "-c" => opts.count_bytes = true,
                "--help"  | "-h" => {
                    stdout.write(MAN_PAGE.as_bytes()).try();
                    return;
                },
                _ => fail(&format!("unknown flag, {}.", arg)),
            }
        } else { // This is a file name
            first_file = arg;
            break;
        }
    }

    opts.default_to();

    if first_file == "" {
        let (lines, words, bytes) = do_count(io::stdin());
        opts.print_count(lines, words, bytes, "stdin");
    } else {
        let mut total_lines = 0;
        let mut total_words = 0;
        let mut total_bytes = 0;

        let single_file = args.len() == 1;

        for path in iter::once(first_file).chain(args) {
            //TODO would be easy to use stdin for - but
            //that is probably something the shell should handle?
            //unix it's all just fds so it's whatever dunno here tho
            //(also - is specific to sh/bash fwiw).

            let file = File::open(&path).try();
            let (lines, words, bytes) = do_count(file);

            total_lines += lines;
            total_words += words;
            total_bytes += bytes;

            opts.print_count(lines, words, bytes, &path);
        }

        if single_file {
            opts.print_count(total_lines, total_words, total_bytes, "total");
        }
    }
}

fn is_whitespace(byte: u8) -> bool {
    //FIXME this works like iswspace w/ default C locale
    //but not good enough for en_US.UTF8 among others

    byte == b'\n' // newline
    || byte == b'\t' // tab
    || byte == b'\r' // cr
    || byte == 0xc // formfeed
    || byte == 0xb // vtab
    || byte == b' ' // space
}

fn do_count<T: std::io::Read>(input: T) -> (u64, u64, u64) {
    let mut line_count = 0;
    let mut word_count = 0;
    let mut byte_count = 0;
    let mut got_space = true;

    for byte_result in input.bytes() {
        if let Ok(byte) = byte_result {
            if byte == b'\n' {
                line_count += 1;
            }

            if is_whitespace(byte) {
                got_space = true;
            } else if got_space {
                got_space = false;
                word_count += 1;
            }

            byte_count += 1;
        }
    }

    (line_count, word_count, byte_count)
}
<|endoftext|>


<commit_before>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![]
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Message(user, text) => {
                callback(irc::protocol::Message {
                    prefix: Some(format!("{}@anony.oob", user.nickname)),
                    command: irc::protocol::Command::Privmsg,
                    args: vec![self.canonical_alias.clone().unwrap()],
                    suffix: Some(text)
                });
            },
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => ()
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(),
            rooms: HashMap::new()
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let mut messages: Vec<irc::protocol::Message> = vec![];
        {
            let appendMsg = |msg: irc::protocol::Message| {
                messages.push(msg);
            };
            match evt.data {
                matrix::events::EventData::Room(room_id, room_event) => {
                    self.room(&room_id).handle_event(room_event, appendMsg);
                },
                _ => println!("Unhandled {:?}", evt)
            }
        }
        for ref msg in messages {
            self.client.send(msg);
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) -> thread::JoinHandle<()> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            for evt in poll.send() {
                channel.send(Event::Matrix(evt));
            };
            channel.send(Event::EndPoll);
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        });
        self.poll_matrix(channel);
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim());
                                    self.client.welcome(username.trim());
                                    self.start_matrix(events.channel());
                                    println!("Logged in {:?}", username);
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.matrix.send(evt);
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: prevent seeing duplicate events<commit_after>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seenEvents: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![]
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Message(user, text) => {
                callback(irc::protocol::Message {
                    prefix: Some(format!("{}@anony.oob", user.nickname)),
                    command: irc::protocol::Command::Privmsg,
                    args: vec![self.canonical_alias.clone().unwrap()],
                    suffix: Some(text)
                });
            },
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => ()
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(),
            rooms: HashMap::new(),
            seenEvents: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seenEvents.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let appendMsg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room(&room_id).handle_event(room_event, appendMsg);
                    },
                    _ => println!("Unhandled {:?}", evt)
                }
            }
            match evt.id {
                Some(id) =>
                    self.seenEvents.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg);
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) -> thread::JoinHandle<()> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            for evt in poll.send() {
                channel.send(Event::Matrix(evt));
            };
            channel.send(Event::EndPoll);
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        });
        self.poll_matrix(channel);
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim());
                                    self.client.welcome(username.trim());
                                    self.start_matrix(events.channel());
                                    println!("Logged in {:?}", username);
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.seenEvents.push(self.matrix.send(evt));
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::convert::From;

pub const FINGERPRINT_SIZE: usize = 1;
pub const BUCKET_SIZE: usize = 4;
const EMPTY_FINGERPRINT_DATA: [u8; FINGERPRINT_SIZE] = [100; FINGERPRINT_SIZE];

// Fingerprint Size is 1 byte so lets remove the Vec
#[derive(PartialEq, Copy, Clone, Hash)]
pub struct Fingerprint {
    pub data: [u8; FINGERPRINT_SIZE],
}

impl Fingerprint {
    /// Attempts to create a new Fingerprint based on the given
    /// number. If the created Fingerprint would be equal to the
    /// empty Fingerprint, None is returned.
    pub fn from_data(data: [u8; FINGERPRINT_SIZE]) -> Option<Fingerprint> {
        let result = Fingerprint { data: data };
        if result.is_empty() {
            None
        } else {
            Some(result)
        }
    }

    /// Returns the empty Fingerprint.
    pub fn empty() -> Fingerprint {
        Fingerprint {
            data: EMPTY_FINGERPRINT_DATA,
        }
    }

    /// Checks if this is the empty Fingerprint.
    pub fn is_empty(&self) -> bool {
        self.data == EMPTY_FINGERPRINT_DATA
    }

    /// Sets the fingerprint value to a previously exported one via an in-memory copy.
    fn slice_copy(&mut self, fingerprint: &[u8]) {
        self.data.copy_from_slice(fingerprint);
    }
}

/// Manages `BUCKET_SIZE` fingerprints at most.
#[derive(Clone)]
pub struct Bucket {
    pub buffer: [Fingerprint; BUCKET_SIZE],
}

impl Bucket {
    /// Creates a new bucket with a pre-allocated buffer.
    pub fn new() -> Bucket {
        Bucket {
            buffer: [Fingerprint::empty(); BUCKET_SIZE],
        }
    }

    /// Inserts the fingerprint into the buffer if the buffer is not full.
    /// This operation is O(1).
    pub fn insert(&mut self, fp: Fingerprint) -> bool {
        for entry in &mut self.buffer {
            if entry.is_empty() {
                *entry = fp;
                return true;
            }
        }
        false
    }

    /// Deletes the given fingerprint from the bucket. This operation is O(1).
    pub fn delete(&mut self, fp: Fingerprint) -> bool {
        match self.get_fingerprint_index(fp) {
            Some(index) => {
                self.buffer[index] = Fingerprint::empty();
                true
            }
            None => false,
        }
    }

    /// Returns the index of the given fingerprint, if its found. O(1)
    pub fn get_fingerprint_index(&self, fp: Fingerprint) -> Option<usize> {
        self.buffer.iter().position(|e| *e == fp)
    }

    /// Returns all current fingerprint data of the current buffer for storage.
    pub fn get_fingerprint_data(&self) -> Vec<u8> {
        self.buffer
            .iter()
            .flat_map(|f| f.data.into_iter())
            .map(|&f| f)
            .collect()
    }
}

impl<'a> From<&'a [u8]> for Bucket {
    /// Constructs a buffer of fingerprints from a set of previously exported fingerprints.
    fn from(fingerprints: &'a [u8]) -> Self {
        let mut buffer = [Fingerprint::empty(); BUCKET_SIZE];
        for (idx, value) in fingerprints.chunks(FINGERPRINT_SIZE).enumerate() {
            buffer[idx].slice_copy(value);
        }
        Bucket { buffer: buffer }
    }
}
<commit_msg>Cloned is more verbose here<commit_after>use std::convert::From;

pub const FINGERPRINT_SIZE: usize = 1;
pub const BUCKET_SIZE: usize = 4;
const EMPTY_FINGERPRINT_DATA: [u8; FINGERPRINT_SIZE] = [100; FINGERPRINT_SIZE];

// Fingerprint Size is 1 byte so lets remove the Vec
#[derive(PartialEq, Copy, Clone, Hash)]
pub struct Fingerprint {
    pub data: [u8; FINGERPRINT_SIZE],
}

impl Fingerprint {
    /// Attempts to create a new Fingerprint based on the given
    /// number. If the created Fingerprint would be equal to the
    /// empty Fingerprint, None is returned.
    pub fn from_data(data: [u8; FINGERPRINT_SIZE]) -> Option<Fingerprint> {
        let result = Fingerprint { data: data };
        if result.is_empty() {
            None
        } else {
            Some(result)
        }
    }

    /// Returns the empty Fingerprint.
    pub fn empty() -> Fingerprint {
        Fingerprint {
            data: EMPTY_FINGERPRINT_DATA,
        }
    }

    /// Checks if this is the empty Fingerprint.
    pub fn is_empty(&self) -> bool {
        self.data == EMPTY_FINGERPRINT_DATA
    }

    /// Sets the fingerprint value to a previously exported one via an in-memory copy.
    fn slice_copy(&mut self, fingerprint: &[u8]) {
        self.data.copy_from_slice(fingerprint);
    }
}

/// Manages `BUCKET_SIZE` fingerprints at most.
#[derive(Clone)]
pub struct Bucket {
    pub buffer: [Fingerprint; BUCKET_SIZE],
}

impl Bucket {
    /// Creates a new bucket with a pre-allocated buffer.
    pub fn new() -> Bucket {
        Bucket {
            buffer: [Fingerprint::empty(); BUCKET_SIZE],
        }
    }

    /// Inserts the fingerprint into the buffer if the buffer is not full.
    /// This operation is O(1).
    pub fn insert(&mut self, fp: Fingerprint) -> bool {
        for entry in &mut self.buffer {
            if entry.is_empty() {
                *entry = fp;
                return true;
            }
        }
        false
    }

    /// Deletes the given fingerprint from the bucket. This operation is O(1).
    pub fn delete(&mut self, fp: Fingerprint) -> bool {
        match self.get_fingerprint_index(fp) {
            Some(index) => {
                self.buffer[index] = Fingerprint::empty();
                true
            }
            None => false,
        }
    }

    /// Returns the index of the given fingerprint, if its found. O(1)
    pub fn get_fingerprint_index(&self, fp: Fingerprint) -> Option<usize> {
        self.buffer.iter().position(|e| *e == fp)
    }

    /// Returns all current fingerprint data of the current buffer for storage.
    pub fn get_fingerprint_data(&self) -> Vec<u8> {
        self.buffer
            .iter()
            .flat_map(|f| f.data.into_iter())
            .cloned()
            .collect()
    }
}

impl<'a> From<&'a [u8]> for Bucket {
    /// Constructs a buffer of fingerprints from a set of previously exported fingerprints.
    fn from(fingerprints: &'a [u8]) -> Self {
        let mut buffer = [Fingerprint::empty(); BUCKET_SIZE];
        for (idx, value) in fingerprints.chunks(FINGERPRINT_SIZE).enumerate() {
            buffer[idx].slice_copy(value);
        }
        Bucket { buffer: buffer }
    }
}
<|endoftext|>


<commit_before>//! Buffers to safely work with audio samples.

use std::iter::{Zip, IntoIterator};
use std::vec::IntoIter;
use std::slice;

use num::Float;

/// A buffer containing `ChannelBuffer` buffers for each input/output.
pub struct AudioBuffer<'a, T: 'a + Float> {
    inputs: Vec<ChannelBuffer<'a, T>>,
    outputs: Vec<ChannelBuffer<'a, T>>,
}

/// Iterator over channel buffers for either inputs or outputs.
pub type ChannelBufferIter<'a, T> = IntoIter<ChannelBuffer<'a, T>>;

impl<'a, T: 'a + Float> AudioBuffer<'a, T> {
    /// Create an `AudioBuffer` from vectors of slices.
    ///
    /// Each vector item represents either an input or output, and contains an array of samples. Eg
    /// if inputs was a vector of size 2 containing slices of size 512, it would hold 2 inputs where
    /// each input holds 512 samples.
    pub fn new(inputs: Vec<&'a mut [T]>, outputs: Vec<&'a mut [T]>) -> AudioBuffer<'a, T> {
        // Creats an input / output for each array in respective Vec
        AudioBuffer {
            inputs: inputs.into_iter().map(|input| ChannelBuffer::new(input)).collect(),
            outputs: outputs.into_iter().map(|output| ChannelBuffer::new(output)).collect()
        }
    }

    /// Create an `AudioBuffer` from raw pointers. Only really useful for interacting with the VST
    /// API.
    pub unsafe fn from_raw(inputs_raw: *mut *mut T, outputs_raw: *mut *mut T, num_inputs: usize, num_outputs: usize, samples: usize) -> AudioBuffer<'a, T> {
        let inputs =
            // Create a slice of type &mut [*mut f32]
            slice::from_raw_parts_mut(inputs_raw, num_inputs).iter()
            // Convert to &mut [&mut [f32]]
            .map(|input| slice::from_raw_parts_mut(*input, samples))
            // Collect into Vec<&mut [f32]>
            .collect();

        let outputs =
            // Create a slice of type &mut [*mut f32]
            slice::from_raw_parts_mut(outputs_raw, num_outputs).iter()
            // Convert to &mut [&mut [f32]]
            .map(|output| slice::from_raw_parts_mut(*output, samples))
            // Collect into Vec<&mut [f32]>
            .collect();

        // Call constructor with vectors
        AudioBuffer::new(inputs, outputs)
    }

    /// Retreieve input at specified index.
    pub fn input(&'a mut self, index: usize) -> Option<&'a mut ChannelBuffer<'a, T>> {
        self.inputs.get_mut(index)
    }

    /// Retreieve output at specified index.
    pub fn output(&'a mut self, index: usize) -> Option<&'a mut ChannelBuffer<'a, T>> {
        self.outputs.get_mut(index)
    }

    /// Create an iterator over all inputs.
    pub fn inputs(self) -> ChannelBufferIter<'a, T> {
        self.inputs.into_iter()
    }

    /// Create an iterator over all outputs.
    pub fn outputs(self) -> ChannelBufferIter<'a, T> {
        self.outputs.into_iter()
    }

    /// Zip together buffers.
    pub fn zip(self) -> Zip<ChannelBufferIter<'a, T>, ChannelBufferIter<'a, T>> {
        self.inputs.into_iter().zip(self.outputs.into_iter())
    }
}

// Maybe Replace this with just a slice?
/// Buffer samples for one channel.
pub struct ChannelBuffer<'a, T: 'a + Float>(&'a mut [T]);

impl<'a, T: 'a + Float> ChannelBuffer<'a, T> {
    /// Construct a new `ChannelBuffer` from a slice.
    pub fn new(data: &'a mut [T]) -> ChannelBuffer<'a, T> {
        ChannelBuffer(data)
    }
}

impl<'a, T: 'a + Float> IntoIterator for ChannelBuffer<'a, T> {
    type Item = &'a mut T;
    type IntoIter = slice::IterMut<'a, T>;

    fn into_iter(self) -> slice::IterMut<'a, T> {
        self.0.iter_mut()
    }
}

#[cfg(test)]
mod tests {
    use buffer::AudioBuffer;

    /// Size of buffers used in tests.
    const SIZE: usize = 1024;

    /// Test that creating and zipping buffers works.
    ///
    /// This test creates a channel for 2 inputs and 2 outputs. The input channels are simply values
    /// from 0 to `SIZE-1` (e.g. [0, 1, 2, 3, 4, .. , SIZE - 1]) and the output channels are just 0.
    /// This test assures that when the buffers are zipped together, the input values do not change.
    #[test]
    fn buffer_zip() {
        let mut in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
        let mut in2 = in1.clone();

        let mut out1 = vec![0.0; SIZE];
        let mut out2 = out1.clone();

        let buffer = AudioBuffer::new(vec![&mut in1, &mut in2],
                                      vec![&mut out1, &mut out2]);

        for (input, output) in buffer.zip() {
            input.into_iter().zip(output.into_iter())
            .fold(0, |acc, (input, output)| {
                assert_eq!(*input - acc as f32, 0.0);
                assert_eq!(*output, 0.0);
                acc + 1
            });
        }
    }

    /// Test that creating buffers from raw pointers works.
    #[test]
    fn from_raw() {
        let mut in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
        let mut in2 = in1.clone();

        let mut out1 = vec![0.0; SIZE];
        let mut out2 = out1.clone();

        let buffer = unsafe {
            AudioBuffer::from_raw(vec![in1.as_mut_ptr(), in2.as_mut_ptr()].as_mut_ptr(),
                                  vec![out1.as_mut_ptr(), out2.as_mut_ptr()].as_mut_ptr(),
                                  2, 2, SIZE)
        };

        for (input, output) in buffer.zip() {
            input.into_iter().zip(output.into_iter())
            .fold(0, |acc, (input, output)| {
                assert_eq!(*input - acc as f32, 0.0);
                assert_eq!(*output, 0.0);
                acc + 1
            });
        }
    }
}
<commit_msg>Breaking change: Replace `ChannelBuffer` with slices<commit_after>//! Buffers to safely work with audio samples.

use std::iter::{Zip, IntoIterator};
use std::vec::IntoIter;
use std::slice;

use num::Float;

/// A buffer containing `ChannelBuffer` buffers for each input/output.
pub struct AudioBuffer<'a, T: 'a + Float> {
    inputs: Vec<&'a mut [T]>,
    outputs: Vec<&'a mut [T]>,
}

/// Iterator over channel buffers for either inputs or outputs.
pub type ChannelBufferIter<'a, T> = IntoIter<&'a mut [T]>;

impl<'a, T: 'a + Float> AudioBuffer<'a, T> {
    /// Create an `AudioBuffer` from vectors of slices.
    ///
    /// Each vector item represents either an input or output, and contains an array of samples. Eg
    /// if inputs was a vector of size 2 containing slices of size 512, it would hold 2 inputs where
    /// each input holds 512 samples.
    pub fn new(inputs: Vec<&'a mut [T]>, outputs: Vec<&'a mut [T]>) -> AudioBuffer<'a, T> {
        AudioBuffer {
            inputs: inputs,
            outputs: outputs,
        }
    }

    /// Create an `AudioBuffer` from raw pointers. Only really useful for interacting with the VST
    /// API.
    pub unsafe fn from_raw(inputs_raw: *mut *mut T, outputs_raw: *mut *mut T, num_inputs: usize, num_outputs: usize, samples: usize) -> AudioBuffer<'a, T> {
        let inputs =
            // Create a slice of type &mut [*mut f32]
            slice::from_raw_parts_mut(inputs_raw, num_inputs).iter()
            // Convert to &mut [&mut [f32]]
            .map(|input| slice::from_raw_parts_mut(*input, samples))
            // Collect into Vec<&mut [f32]>
            .collect();

        let outputs =
            // Create a slice of type &mut [*mut f32]
            slice::from_raw_parts_mut(outputs_raw, num_outputs).iter()
            // Convert to &mut [&mut [f32]]
            .map(|output| slice::from_raw_parts_mut(*output, samples))
            // Collect into Vec<&mut [f32]>
            .collect();

        // Call constructor with vectors
        AudioBuffer::new(inputs, outputs)
    }

    /// Return a reference to all inputs.
    pub fn inputs(&'a mut self) -> &'a mut Vec<&'a mut [T]> {
        &mut self.inputs
    }

    /// Return a reference to all outputs.
    pub fn outputs(&'a mut self) -> &'a mut Vec<&'a mut [T]> {
        &mut self.outputs
    }

    /// Zip together buffers.
    pub fn zip(self) -> Zip<ChannelBufferIter<'a, T>, ChannelBufferIter<'a, T>> {
        self.inputs.into_iter().zip(self.outputs.into_iter())
    }
}

#[cfg(test)]
mod tests {
    use buffer::AudioBuffer;

    /// Size of buffers used in tests.
    const SIZE: usize = 1024;

    /// Test that creating and zipping buffers works.
    ///
    /// This test creates a channel for 2 inputs and 2 outputs. The input channels are simply values
    /// from 0 to `SIZE-1` (e.g. [0, 1, 2, 3, 4, .. , SIZE - 1]) and the output channels are just 0.
    /// This test assures that when the buffers are zipped together, the input values do not change.
    #[test]
    fn buffer_zip() {
        let mut in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
        let mut in2 = in1.clone();

        let mut out1 = vec![0.0; SIZE];
        let mut out2 = out1.clone();

        let buffer = AudioBuffer::new(vec![&mut in1, &mut in2],
                                      vec![&mut out1, &mut out2]);

        for (input, output) in buffer.zip() {
            input.into_iter().zip(output.into_iter())
            .fold(0, |acc, (input, output)| {
                assert_eq!(*input - acc as f32, 0.0);
                assert_eq!(*output, 0.0);
                acc + 1
            });
        }
    }

    /// Test that creating buffers from raw pointers works.
    #[test]
    fn from_raw() {
        let mut in1: Vec<f32> = (0..SIZE).map(|x| x as f32).collect();
        let mut in2 = in1.clone();

        let mut out1 = vec![0.0; SIZE];
        let mut out2 = out1.clone();

        let buffer = unsafe {
            AudioBuffer::from_raw(vec![in1.as_mut_ptr(), in2.as_mut_ptr()].as_mut_ptr(),
                                  vec![out1.as_mut_ptr(), out2.as_mut_ptr()].as_mut_ptr(),
                                  2, 2, SIZE)
        };

        for (input, output) in buffer.zip() {
            input.into_iter().zip(output.into_iter())
            .fold(0, |acc, (input, output)| {
                assert_eq!(*input - acc as f32, 0.0);
                assert_eq!(*output, 0.0);
                acc + 1
            });
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{DEFAULT_BUILD_DIR, DEFAULT_STORAGE_DIR};
use move_coverage::{coverage_map::CoverageMap, summary::summarize_inst_cov};
use move_lang::test_utils::*;
use std::{
    env,
    fs::{self, File},
    io::{self, BufRead, Write},
    path::Path,
    process::Command,
};
use vm::file_format::CompiledModule;

/// Basic datatest testing framework for the CLI. The `run_one` entrypoint expects
/// an `args.txt` file with arguments that the `move` binary understands (one set
/// of arguments per line). The testing framework runs the commands, compares the
/// result to the expected output, and runs `move clean` to discard resources,
/// modules, and event data created by running the test.

const EXP_EXT: &str = "exp";

/// If this env var is set, `move clean` will not be run after each test.
/// this is useful if you want to look at the `storage` or `move_events`
/// produced by a test. However, you'll have to manually run `move clean`
/// before re-running the test.
const NO_MOVE_CLEAN: &str = "NO_MOVE_CLEAN";
/// If either of these env vars is set, the test harness overwrites the
/// old .exp files with the output instead of checking them against the
/// output.
const UPDATE_BASELINE: &str = "UPDATE_BASELINE";
const UB: &str = "UB";

/// Name of the environment variable we need to set in order to get tracing
/// enabled in the move VM.
const MOVE_VM_TRACING_ENV_VAR_NAME: &str = "MOVE_VM_TRACE";

/// The default file name for the runtime to dump the execution trace to.
/// The trace will be used by the coverage tool if --track-cov is set.
/// If --track-cov is not set, then no trace file will be produced.
const DEFAULT_TRACE_FILE: &str = "trace";

fn format_diff(expected: String, actual: String) -> String {
    use difference::*;

    let changeset = Changeset::new(&expected, &actual, "\n");

    let mut ret = String::new();

    for seq in changeset.diffs {
        match &seq {
            Difference::Same(x) => {
                ret.push_str(x);
                ret.push_str("\n");
            }
            Difference::Add(x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str("\n");
            }
            Difference::Rem(x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str("\n");
            }
        }
    }
    ret
}

fn show_coverage(trace_file: &Path, storage_dir: &Path) -> anyhow::Result<()> {
    // collect modules
    let mut modules: Vec<CompiledModule> = Vec::new();
    for entry in move_lang::find_filenames(&[storage_dir.to_str().unwrap().to_owned()], |fpath| {
        fpath.extension().map_or(false, |e| e == "mv")
    })? {
        let bytecode_bytes = fs::read(entry).unwrap();
        let compiled_module = CompiledModule::deserialize(&bytecode_bytes).unwrap();
        modules.push(compiled_module);
    }

    // collect trace
    let coverage_map = CoverageMap::from_trace_file(trace_file).to_unified_exec_map();

    // summarize
    let mut summary_writer: Box<dyn Write> = Box::new(io::stdout());
    for module in modules.iter() {
        let module_summary = summarize_inst_cov(module, &coverage_map);
        module_summary.summarize_human(&mut summary_writer, true)?;
    }

    Ok(())
}

/// Run the `args_path` batch file with`cli_binary`
pub fn run_one(args_path: &Path, cli_binary: &str, track_cov: bool) -> anyhow::Result<()> {
    let args_file = io::BufReader::new(File::open(args_path)?).lines();
    // path where we will run the binary
    let exe_dir = args_path.parent().unwrap();
    let cli_binary_path = Path::new(cli_binary).canonicalize()?;
    let storage_dir = Path::new(exe_dir).join(DEFAULT_STORAGE_DIR);
    let build_output = Path::new(exe_dir).join(DEFAULT_BUILD_DIR);
    if storage_dir.exists() || build_output.exists() {
        // need to clean before testing
        Command::new(cli_binary_path.clone())
            .current_dir(exe_dir)
            .arg("clean")
            .output()?;
    }
    let mut output = "".to_string();
    for args_line in args_file {
        let args_line = args_line?;
        if args_line.starts_with('#') {
            // allow comments in args.txt
            continue;
        }
        let args_iter: Vec<&str> = args_line.split_whitespace().collect();
        if args_iter.is_empty() {
            // allow blank lines in args.txt
            continue;
        }

        // enable tracing in the VM by setting the env var.
        // for tracing file path: always use the absolute path so we do not need
        // to worry about where the VM is executed.
        let mut trace_file = env::current_dir()?;
        trace_file.push(&storage_dir);
        trace_file.push(DEFAULT_TRACE_FILE);
        if track_cov {
            env::set_var(MOVE_VM_TRACING_ENV_VAR_NAME, trace_file.as_os_str());
        } else if env::var_os(MOVE_VM_TRACING_ENV_VAR_NAME).is_some() {
            // this check prevents cascading the coverage tracking flag.
            // in particular, if
            //   1. we run with move-cli test <path-to-args-A.txt> --track-cov, and
            //   2. in this <args-A.txt>, there is another command: test <args-B.txt>
            // then, when running <args-B.txt>, coverage will not be tracked nor printed
            env::remove_var(MOVE_VM_TRACING_ENV_VAR_NAME);
        }

        let cmd_output = Command::new(cli_binary_path.clone())
            .current_dir(exe_dir)
            .args(args_iter)
            .output()?;
        output += &format!("Command `{}`:\n", args_line);
        output += std::str::from_utf8(&cmd_output.stdout)?;
        output += std::str::from_utf8(&cmd_output.stderr)?;

        // show coverage information
        if track_cov && trace_file.exists() {
            if !trace_file.exists() {
                eprintln!("Trace file {} not found", trace_file.to_string_lossy());
                eprintln!("Coverage is only applicable to the RUN command in args.txt");
            } else {
                show_coverage(Path::new(&trace_file), Path::new(&storage_dir))?;
            }
        }
    }

    // post-test cleanup and cleanup checks
    // check that the test command didn't create a src dir

    let run_move_clean = !read_bool_var(NO_MOVE_CLEAN);
    if run_move_clean {
        // run `move clean` to ensure that temporary state is cleaned up
        Command::new(cli_binary_path)
            .current_dir(exe_dir)
            .arg("clean")
            .output()?;
        // check that storage was deleted
        assert!(
            !storage_dir.exists(),
            "`move clean` failed to eliminate {} directory",
            DEFAULT_STORAGE_DIR
        );
        assert!(
            !storage_dir.exists(),
            "`move clean` failed to eliminate {} directory",
            DEFAULT_BUILD_DIR
        );
    }

    let update_baseline = read_bool_var(UPDATE_BASELINE) || read_bool_var(UB);
    let exp_path = args_path.with_extension(EXP_EXT);
    if update_baseline {
        fs::write(exp_path, &output)?;
        return Ok(());
    }
    // compare output and exp_file
    let expected_output = fs::read_to_string(exp_path).unwrap_or_else(|_| "".to_string());
    if expected_output != output {
        anyhow::bail!(
            "Expected output differs from actual output:\n{}",
            format_diff(expected_output, output)
        )
    } else {
        Ok(())
    }
}

pub fn run_all(args_path: &str, cli_binary: &str, track_cov: bool) -> anyhow::Result<()> {
    let mut test_total = 0;
    let mut test_passed = 0;
    for entry in move_lang::find_filenames(&[args_path.to_owned()], |fpath| {
        fpath.file_name().expect("unexpected file entry path") == "args.txt"
    })? {
        match run_one(Path::new(&entry), cli_binary, track_cov) {
            Ok(_) => test_passed += 1,
            Err(ex) => eprintln!("Test {} failed with error: {}", entry, ex),
        }
        test_total += 1;
    }
    println!("{} / {} test(s) passed.", test_total, test_passed);

    // if any test fails, bail
    let test_failed = test_total - test_passed;
    if test_failed != 0 {
        anyhow::bail!("{} / {} test(s) failed.", test_failed, test_total)
    } else {
        Ok(())
    }
}
<commit_msg>[move-cli] filter out package modules when showing coverage info<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{DEFAULT_BUILD_DIR, DEFAULT_PACKAGE_DIR, DEFAULT_STORAGE_DIR};
use anyhow::anyhow;
use move_coverage::{coverage_map::CoverageMap, summary::summarize_inst_cov};
use move_lang::{extension_equals, path_to_string, test_utils::*, MOVE_COMPILED_EXTENSION};
use std::{
    collections::HashSet,
    env,
    fs::{self, File},
    io::{self, BufRead, Write},
    path::{Path, PathBuf},
    process::Command,
};
use vm::file_format::CompiledModule;

/// Basic datatest testing framework for the CLI. The `run_one` entrypoint expects
/// an `args.txt` file with arguments that the `move` binary understands (one set
/// of arguments per line). The testing framework runs the commands, compares the
/// result to the expected output, and runs `move clean` to discard resources,
/// modules, and event data created by running the test.

const EXP_EXT: &str = "exp";

/// If this env var is set, `move clean` will not be run after each test.
/// this is useful if you want to look at the `storage` or `move_events`
/// produced by a test. However, you'll have to manually run `move clean`
/// before re-running the test.
const NO_MOVE_CLEAN: &str = "NO_MOVE_CLEAN";
/// If either of these env vars is set, the test harness overwrites the
/// old .exp files with the output instead of checking them against the
/// output.
const UPDATE_BASELINE: &str = "UPDATE_BASELINE";
const UB: &str = "UB";

/// Name of the environment variable we need to set in order to get tracing
/// enabled in the move VM.
const MOVE_VM_TRACING_ENV_VAR_NAME: &str = "MOVE_VM_TRACE";

/// The default file name for the runtime to dump the execution trace to.
/// The trace will be used by the coverage tool if --track-cov is set.
/// If --track-cov is not set, then no trace file will be produced.
const DEFAULT_TRACE_FILE: &str = "trace";

fn format_diff(expected: String, actual: String) -> String {
    use difference::*;

    let changeset = Changeset::new(&expected, &actual, "\n");

    let mut ret = String::new();

    for seq in changeset.diffs {
        match &seq {
            Difference::Same(x) => {
                ret.push_str(x);
                ret.push_str("\n");
            }
            Difference::Add(x) => {
                ret.push_str("\x1B[92m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str("\n");
            }
            Difference::Rem(x) => {
                ret.push_str("\x1B[91m");
                ret.push_str(x);
                ret.push_str("\x1B[0m");
                ret.push_str("\n");
            }
        }
    }
    ret
}

fn show_coverage(trace_file: &Path, build_dir: &Path, storage_dir: &Path) -> anyhow::Result<()> {
    fn find_compiled_move_filenames(path: &Path) -> anyhow::Result<Vec<String>> {
        if path.exists() {
            move_lang::find_filenames(&[path_to_string(path)?], |fpath| {
                extension_equals(fpath, MOVE_COMPILED_EXTENSION)
            })
        } else {
            Ok(vec![])
        }
    }

    // collect modules compiled for packages (to be filtered out)
    let pkg_modules: HashSet<_> =
        find_compiled_move_filenames(&build_dir.join(DEFAULT_PACKAGE_DIR))?
            .into_iter()
            .map(|entry| PathBuf::from(entry).file_name().unwrap().to_owned())
            .collect();

    // collect modules published minus modules compiled for packages
    let mut modules: Vec<CompiledModule> = Vec::new();
    for entry in move_lang::find_filenames(&[path_to_string(storage_dir)?], |fpath| {
        extension_equals(fpath, MOVE_COMPILED_EXTENSION)
            && !pkg_modules.contains(fpath.file_name().unwrap())
    })? {
        let bytecode_bytes = fs::read(&entry)?;
        let compiled_module = CompiledModule::deserialize(&bytecode_bytes)
            .map_err(|e| anyhow!("Failure deserializing module {:?}: {:?}", entry, e))?;
        modules.push(compiled_module);
    }

    // collect trace
    let coverage_map = CoverageMap::from_trace_file(trace_file).to_unified_exec_map();

    // summarize
    let mut summary_writer: Box<dyn Write> = Box::new(io::stdout());
    for module in modules.iter() {
        let module_summary = summarize_inst_cov(module, &coverage_map);
        module_summary.summarize_human(&mut summary_writer, true)?;
    }

    Ok(())
}

/// Run the `args_path` batch file with`cli_binary`
pub fn run_one(args_path: &Path, cli_binary: &str, track_cov: bool) -> anyhow::Result<()> {
    let args_file = io::BufReader::new(File::open(args_path)?).lines();
    // path where we will run the binary
    let exe_dir = args_path.parent().unwrap();
    let cli_binary_path = Path::new(cli_binary).canonicalize()?;
    let storage_dir = Path::new(exe_dir).join(DEFAULT_STORAGE_DIR);
    let build_output = Path::new(exe_dir).join(DEFAULT_BUILD_DIR);
    if storage_dir.exists() || build_output.exists() {
        // need to clean before testing
        Command::new(cli_binary_path.clone())
            .current_dir(exe_dir)
            .arg("clean")
            .output()?;
    }
    let mut output = "".to_string();
    for args_line in args_file {
        let args_line = args_line?;
        if args_line.starts_with('#') {
            // allow comments in args.txt
            continue;
        }
        let args_iter: Vec<&str> = args_line.split_whitespace().collect();
        if args_iter.is_empty() {
            // allow blank lines in args.txt
            continue;
        }

        // enable tracing in the VM by setting the env var.
        // for tracing file path: always use the absolute path so we do not need
        // to worry about where the VM is executed.
        let mut trace_file = env::current_dir()?;
        trace_file.push(&storage_dir);
        trace_file.push(DEFAULT_TRACE_FILE);
        if track_cov {
            env::set_var(MOVE_VM_TRACING_ENV_VAR_NAME, trace_file.as_os_str());
        } else if env::var_os(MOVE_VM_TRACING_ENV_VAR_NAME).is_some() {
            // this check prevents cascading the coverage tracking flag.
            // in particular, if
            //   1. we run with move-cli test <path-to-args-A.txt> --track-cov, and
            //   2. in this <args-A.txt>, there is another command: test <args-B.txt>
            // then, when running <args-B.txt>, coverage will not be tracked nor printed
            env::remove_var(MOVE_VM_TRACING_ENV_VAR_NAME);
        }

        let cmd_output = Command::new(cli_binary_path.clone())
            .current_dir(exe_dir)
            .args(args_iter)
            .output()?;
        output += &format!("Command `{}`:\n", args_line);
        output += std::str::from_utf8(&cmd_output.stdout)?;
        output += std::str::from_utf8(&cmd_output.stderr)?;

        // show coverage information
        if track_cov && trace_file.exists() {
            if !trace_file.exists() {
                eprintln!("Trace file {} not found", trace_file.to_string_lossy());
                eprintln!("Coverage is only applicable to the RUN command in args.txt");
            } else {
                show_coverage(&trace_file, &build_output, &storage_dir)?;
            }
        }
    }

    // post-test cleanup and cleanup checks
    // check that the test command didn't create a src dir

    let run_move_clean = !read_bool_var(NO_MOVE_CLEAN);
    if run_move_clean {
        // run `move clean` to ensure that temporary state is cleaned up
        Command::new(cli_binary_path)
            .current_dir(exe_dir)
            .arg("clean")
            .output()?;
        // check that storage was deleted
        assert!(
            !storage_dir.exists(),
            "`move clean` failed to eliminate {} directory",
            DEFAULT_STORAGE_DIR
        );
        assert!(
            !storage_dir.exists(),
            "`move clean` failed to eliminate {} directory",
            DEFAULT_BUILD_DIR
        );
    }

    let update_baseline = read_bool_var(UPDATE_BASELINE) || read_bool_var(UB);
    let exp_path = args_path.with_extension(EXP_EXT);
    if update_baseline {
        fs::write(exp_path, &output)?;
        return Ok(());
    }
    // compare output and exp_file
    let expected_output = fs::read_to_string(exp_path).unwrap_or_else(|_| "".to_string());
    if expected_output != output {
        anyhow::bail!(
            "Expected output differs from actual output:\n{}",
            format_diff(expected_output, output)
        )
    } else {
        Ok(())
    }
}

pub fn run_all(args_path: &str, cli_binary: &str, track_cov: bool) -> anyhow::Result<()> {
    let mut test_total = 0;
    let mut test_passed = 0;
    for entry in move_lang::find_filenames(&[args_path.to_owned()], |fpath| {
        fpath.file_name().expect("unexpected file entry path") == "args.txt"
    })? {
        match run_one(Path::new(&entry), cli_binary, track_cov) {
            Ok(_) => test_passed += 1,
            Err(ex) => eprintln!("Test {} failed with error: {}", entry, ex),
        }
        test_total += 1;
    }
    println!("{} / {} test(s) passed.", test_total, test_passed);

    // if any test fails, bail
    let test_failed = test_total - test_passed;
    if test_failed != 0 {
        anyhow::bail!("{} / {} test(s) failed.", test_failed, test_total)
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate minifb;
use minifb::*;
use c64::cia;

// C64 keyboard
pub struct Keyboard
{
    keys: u8,
}

impl Keyboard
{
    pub fn new() -> Keyboard
    {
        Keyboard
        {
            keys: 0,
        }
    }

    pub fn update_keystates(&mut self, window: &Window, cia1: &mut cia::CIAShared)
    {
        // TODO: actual key state saving should likely be done outside of vsync;
        // only update CIA key matrix in vstate
        cia1.borrow_mut().key_matrix;
        cia1.borrow_mut().rev_matrix;

        if window.is_key_down(Key::Key0) { println!("0"); }
        if window.is_key_down(Key::Key1) { println!("1"); }
        if window.is_key_down(Key::Key2) { println!("2"); }
        if window.is_key_down(Key::Key3) { println!("3"); }
        if window.is_key_down(Key::Key4) { println!("4"); }
        if window.is_key_down(Key::Key5) { println!("5"); }
        if window.is_key_down(Key::Key6) { println!("6"); }
        if window.is_key_down(Key::Key7) { println!("7"); }
        if window.is_key_down(Key::Key8) { println!("8"); }
        if window.is_key_down(Key::Key9) { println!("9"); }

        if window.is_key_down(Key::A) { println!("A"); }
        if window.is_key_down(Key::B) { println!("B"); }
        if window.is_key_down(Key::C) { println!("C"); }
        if window.is_key_down(Key::D) { println!("D"); }
        if window.is_key_down(Key::E) { println!("E"); }
        if window.is_key_down(Key::F) { println!("F"); }
        if window.is_key_down(Key::G) { println!("G"); }
        if window.is_key_down(Key::H) { println!("H"); }
        if window.is_key_down(Key::I) { println!("I"); }
        if window.is_key_down(Key::J) { println!("J"); }
        if window.is_key_down(Key::K) { println!("K"); }
        if window.is_key_down(Key::L) { println!("L"); }
        if window.is_key_down(Key::M) { println!("M"); }
        if window.is_key_down(Key::N) { println!("N"); }
        if window.is_key_down(Key::O) { println!("O"); }
        if window.is_key_down(Key::P) { println!("P"); }
        if window.is_key_down(Key::Q) { println!("Q"); }
        if window.is_key_down(Key::R) { println!("R"); }
        if window.is_key_down(Key::S) { println!("S"); }
        if window.is_key_down(Key::T) { println!("T"); }
        if window.is_key_down(Key::U) { println!("U"); }
        if window.is_key_down(Key::V) { println!("V"); }
        if window.is_key_down(Key::W) { println!("W"); }
        if window.is_key_down(Key::X) { println!("X"); }
        if window.is_key_down(Key::Y) { println!("Y"); }
        if window.is_key_down(Key::Z) { println!("Z"); }

        if window.is_key_down(Key::F1) { println!("F1"); }
        if window.is_key_down(Key::F2) { println!("F2"); }
        if window.is_key_down(Key::F3) { println!("F3"); }
        if window.is_key_down(Key::F4) { println!("F4"); }
        if window.is_key_down(Key::F5) { println!("F5"); }
        if window.is_key_down(Key::F6) { println!("F6"); }
        if window.is_key_down(Key::F7) { println!("F7"); }
        if window.is_key_down(Key::F8) { println!("F8"); }

        if window.is_key_down(Key::Down) { println!("Down"); }
        if window.is_key_down(Key::Left) { println!("Left"); }
        if window.is_key_down(Key::Right) { println!("Right"); }
        if window.is_key_down(Key::Up) { println!("Up"); }

        // iterating over all keys is crawling-slow for some reason...
       /* for key in window.get_keys().unwrap()
        {
            match key {
                minifb::Key::A => println!("a"),
                minifb::Key::B => println!("b"),
                _ => (), }
        } */
    }
}
<commit_msg>C64 keyboard matrix mapping<commit_after>extern crate minifb;
use minifb::*;
use c64::cia;

/*
 C64 keyboard map:

 Bit |    7      6   5     4      3     2        1       0
-----+------------------------------------------------------
  7  |   STOP    Q   C=  SPACE    2    CTRL     <-       1
  6  |    /      ^   =   RSHIFT  HOME   ;       *      POUND
  5  |    ,      @   "     .      -     L       P        +
  4  |    N      O   K     M      0     J       I        9
  3  |    V      U   H     B      8     G       Y        7
  2  |    X      T   F     C      6     D       R        5
  1  |  LSHIFT   E   S     Z      4     A       W        3
  0  |  CRSR-DN  F5  F3    F1     F7  CRSR-RT  RETURN  DELETE
*/
pub struct Keyboard
{
    keys: u8,
}

impl Keyboard
{
    pub fn new() -> Keyboard
    {
        Keyboard
        {
            keys: 0,
        }
    }

    pub fn update_keystates(&mut self, window: &Window, cia1: &mut cia::CIAShared)
    {
        let mut c64_keycode: u8 = 0xFF;

        if window.is_key_down(Key::Key0) { c64_keycode = self.keycode_to_c64(Key::Key0); }
        if window.is_key_down(Key::Key1) { c64_keycode = self.keycode_to_c64(Key::Key1); }
        if window.is_key_down(Key::Key2) { c64_keycode = self.keycode_to_c64(Key::Key2); }
        if window.is_key_down(Key::Key3) { c64_keycode = self.keycode_to_c64(Key::Key3); }
        if window.is_key_down(Key::Key4) { c64_keycode = self.keycode_to_c64(Key::Key4); }
        if window.is_key_down(Key::Key5) { c64_keycode = self.keycode_to_c64(Key::Key5); }
        if window.is_key_down(Key::Key6) { c64_keycode = self.keycode_to_c64(Key::Key6); }
        if window.is_key_down(Key::Key7) { c64_keycode = self.keycode_to_c64(Key::Key7); }
        if window.is_key_down(Key::Key8) { c64_keycode = self.keycode_to_c64(Key::Key8); }
        if window.is_key_down(Key::Key9) { c64_keycode = self.keycode_to_c64(Key::Key9); }

        if window.is_key_down(Key::A) { c64_keycode = self.keycode_to_c64(Key::A); }
        if window.is_key_down(Key::B) { c64_keycode = self.keycode_to_c64(Key::B); }
        if window.is_key_down(Key::C) { c64_keycode = self.keycode_to_c64(Key::C); }
        if window.is_key_down(Key::D) { c64_keycode = self.keycode_to_c64(Key::D); }
        if window.is_key_down(Key::E) { c64_keycode = self.keycode_to_c64(Key::E); }
        if window.is_key_down(Key::F) { c64_keycode = self.keycode_to_c64(Key::F); }
        if window.is_key_down(Key::G) { c64_keycode = self.keycode_to_c64(Key::G); }
        if window.is_key_down(Key::H) { c64_keycode = self.keycode_to_c64(Key::H); }
        if window.is_key_down(Key::I) { c64_keycode = self.keycode_to_c64(Key::I); }
        if window.is_key_down(Key::J) { c64_keycode = self.keycode_to_c64(Key::J); }
        if window.is_key_down(Key::K) { c64_keycode = self.keycode_to_c64(Key::K); }
        if window.is_key_down(Key::L) { c64_keycode = self.keycode_to_c64(Key::L); }
        if window.is_key_down(Key::M) { c64_keycode = self.keycode_to_c64(Key::M); }
        if window.is_key_down(Key::N) { c64_keycode = self.keycode_to_c64(Key::N); }
        if window.is_key_down(Key::O) { c64_keycode = self.keycode_to_c64(Key::O); }
        if window.is_key_down(Key::P) { c64_keycode = self.keycode_to_c64(Key::P); }
        if window.is_key_down(Key::Q) { c64_keycode = self.keycode_to_c64(Key::Q); }
        if window.is_key_down(Key::R) { c64_keycode = self.keycode_to_c64(Key::R); }
        if window.is_key_down(Key::S) { c64_keycode = self.keycode_to_c64(Key::S); }
        if window.is_key_down(Key::T) { c64_keycode = self.keycode_to_c64(Key::T); }
        if window.is_key_down(Key::U) { c64_keycode = self.keycode_to_c64(Key::U); }
        if window.is_key_down(Key::V) { c64_keycode = self.keycode_to_c64(Key::V); }
        if window.is_key_down(Key::W) { c64_keycode = self.keycode_to_c64(Key::W); }
        if window.is_key_down(Key::X) { c64_keycode = self.keycode_to_c64(Key::X); }
        if window.is_key_down(Key::Y) { c64_keycode = self.keycode_to_c64(Key::Y); }
        if window.is_key_down(Key::Z) { c64_keycode = self.keycode_to_c64(Key::Z); }

        if window.is_key_down(Key::F1) { c64_keycode = self.keycode_to_c64(Key::F1); }
        if window.is_key_down(Key::F2) { c64_keycode = self.keycode_to_c64(Key::F2); }
        if window.is_key_down(Key::F3) { c64_keycode = self.keycode_to_c64(Key::F3); }
        if window.is_key_down(Key::F4) { c64_keycode = self.keycode_to_c64(Key::F4); }
        if window.is_key_down(Key::F5) { c64_keycode = self.keycode_to_c64(Key::F5); }
        if window.is_key_down(Key::F6) { c64_keycode = self.keycode_to_c64(Key::F6); }
        if window.is_key_down(Key::F7) { c64_keycode = self.keycode_to_c64(Key::F7); }
        if window.is_key_down(Key::F8) { c64_keycode = self.keycode_to_c64(Key::F8); }

        if window.is_key_down(Key::Down)  { c64_keycode = self.keycode_to_c64(Key::Down); }
        if window.is_key_down(Key::Up)    { c64_keycode = self.keycode_to_c64(Key::Up); }
        if window.is_key_down(Key::Right) { c64_keycode = self.keycode_to_c64(Key::Right); }
        if window.is_key_down(Key::Left)  { c64_keycode = self.keycode_to_c64(Key::Left); }
        if window.is_key_down(Key::Space) { c64_keycode = self.keycode_to_c64(Key::Space); }

        if window.is_key_down(Key::Tab)      { c64_keycode = self.keycode_to_c64(Key::Tab);      }
        if window.is_key_down(Key::LeftCtrl) { c64_keycode = self.keycode_to_c64(Key::LeftCtrl); }

        if c64_keycode != 0xFF
        {
            let c64_bit  = c64_keycode & 7;
            let c64_byte = (c64_keycode >> 3) & 7;

            // key is shifted?
            if (c64_keycode & 0x80) != 0
            {
                cia1.borrow_mut().key_matrix[6] &= 0xEF;
                cia1.borrow_mut().rev_matrix[4] &= 0xBF;
            }

            cia1.borrow_mut().key_matrix[c64_byte as usize] &= !(1 << c64_bit);
            cia1.borrow_mut().rev_matrix[c64_bit as usize]  &= !(1 << c64_byte);
        }
        // iterating over all keys is crawling-slow for some reason...
       /* for key in window.get_keys().unwrap()
        {
            match key {
                minifb::Key::A => println!("a"),
                minifb::Key::B => println!("b"),
                _ => (), }
        } */
    }

    fn keycode_to_c64(&self, keycode: Key) -> u8
    {
        // fetch key's bit combination as represented in C64 keyboard matrix
        let to_c64 = |row_bit: u8, col_bit: u8| (row_bit << 3) | col_bit;

        match keycode
        {
            Key::Key0 => to_c64(4, 3),
            Key::Key1 => to_c64(7, 0),
            Key::Key2 => to_c64(7, 3),
            Key::Key3 => to_c64(1, 0),
            Key::Key4 => to_c64(1, 3),
            Key::Key5 => to_c64(2, 0),
            Key::Key6 => to_c64(2, 3),
            Key::Key7 => to_c64(3, 0),
            Key::Key8 => to_c64(3, 3),
            Key::Key9 => to_c64(4, 0),
            Key::A => to_c64(1, 2),
            Key::B => to_c64(3, 4),
            Key::C => to_c64(2, 4),
            Key::D => to_c64(2, 2),
            Key::E => to_c64(1, 6),
            Key::F => to_c64(2, 5),
            Key::G => to_c64(3, 2),
            Key::H => to_c64(3, 5),
            Key::I => to_c64(4, 1),
            Key::J => to_c64(4, 2),
            Key::K => to_c64(4, 5),
            Key::L => to_c64(5, 2),
            Key::M => to_c64(4, 4),
            Key::N => to_c64(4, 7),
            Key::O => to_c64(4, 6),
            Key::P => to_c64(5, 1),
            Key::Q => to_c64(7, 6),
            Key::R => to_c64(2, 1),
            Key::S => to_c64(1, 5),
            Key::T => to_c64(2, 6),
            Key::U => to_c64(3, 6),
            Key::V => to_c64(3, 7),
            Key::W => to_c64(1, 1),
            Key::X => to_c64(2, 7),
            Key::Y => to_c64(3, 1),
            Key::Z => to_c64(1, 4),
            Key::F1 => to_c64(0, 4),
            Key::F2 => to_c64(0, 4) | 0x80,
            Key::F3 => to_c64(0, 5),
            Key::F4 => to_c64(0, 5) | 0x80,
            Key::F5 => to_c64(0, 6),
            Key::F6 => to_c64(0, 6) | 0x80,
            Key::F7 => to_c64(0, 3),
            Key::F8 => to_c64(0, 3) | 0x80,
            Key::Down  => to_c64(0,7),
            Key::Up    => to_c64(0,7) | 0x80,
            Key::Right => to_c64(0,2),
            Key::Left  => to_c64(0,2) | 0x80,
            Key::Space => to_c64(7,4),
            // Control key
            Key::Tab => to_c64(7, 2),
            // Commodore key
            Key::LeftCtrl => to_c64(7, 5),
            _ => panic!("Unsupported key")
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![allow(unstable)]

extern crate forkallcc;

use std::borrow::ToOwned;
use forkallcc::{Cont, call_cc};

struct Backtrack {
    checkpoint: Option<Cont<bool>>,
}

impl Backtrack {
    fn new() -> Backtrack {
        Backtrack {
            checkpoint: None,
        }
    }

    fn guess(&mut self) -> bool {
        call_cc(|k| {
            self.checkpoint = Some(k);
            true
        })
    }

    fn fail(&self) -> ! {
        match self.checkpoint {
            Some(ref k) => k.invoke(false),
            None => panic!("Nothing to be done."),
        }
    }
}

fn factor(n: u32) -> (u32, u32) {
    fn integer(bt: &mut Backtrack, m: u32, n: u32) -> u32 {
        for i in range(m, n) {
            if bt.guess() {
                return i;
            }
        }
        bt.fail();
    }

    let mut bt = Backtrack::new();
    let i = integer(&mut bt, 2, 100);
    let j = integer(&mut bt, 2, 100);

    if i*j != n {
        bt.fail();
    }

    (i, j)
}

fn factor_391() {
    const N: u32 = 391;
    let (i, j) = factor(N);
    println!("{} * {} = {}\n", i, j, N);

    assert!(i != 1);
    assert!(j != 1);
    assert_eq!(i * j, N);
}

fn solve_maze() {
    const MAZE_SIZE: i32 = 15;

    let mut maze = "\
        X ------------+\n\
        |       |     |\n\
        |--+  | |   | |\n\
        |  |  | | --+ |\n\
        |     |     | |\n\
        |-+---+--+- | |\n\
        | |      |    |\n\
        | | | ---+-+- |\n\
        |   |      |  |\n\
        | +-+-+--|    |\n\
        | |   |  |--- |\n\
        |     |       |\n\
        |--- -+-------|\n\
        |              \n\
        +------------- \n".to_owned().into_bytes();

    let mut bt = Backtrack::new();
    let mut x = 0;
    let mut y = 0;

    while (x != MAZE_SIZE-1) || (y != MAZE_SIZE-1) {
             if bt.guess() { x += 1; }
        else if bt.guess() { x -= 1; }
        else if bt.guess() { y += 1; }
        else               { y -= 1; }

        if (x < 0) || (x >= MAZE_SIZE) || (y < 0) || (y >= MAZE_SIZE) {
            bt.fail();
        }

        let i = (y*(MAZE_SIZE+1) + x) as usize;
        if maze[i] != b' ' {
            bt.fail();
        }

        maze[i] = b'X';
    }

    for c in String::from_utf8(maze).unwrap().chars() {
        if c == 'X' {
            print!("\x1B[1;32mX\x1B[0m");
        } else {
            print!("{}", c);
        }
    }
}

fn main() {
    factor_391();
    solve_maze();
}
<commit_msg>cleanup<commit_after>#![deny(warnings)]
#![allow(unstable)]

extern crate forkallcc;

use std::borrow::ToOwned;
use forkallcc::{Cont, call_cc};

struct Backtrack {
    checkpoint: Option<Cont<bool>>,
}

impl Backtrack {
    fn new() -> Backtrack {
        Backtrack {
            checkpoint: None,
        }
    }

    fn fail(&self) -> ! {
        match self.checkpoint {
            Some(ref k) => k.invoke(false),
            None => panic!("Nothing to be done."),
        }
    }

    fn guess(&mut self) -> bool {
        call_cc(|k| {
            self.checkpoint = Some(k);
            true
        })
    }

    fn guess_from<I>(&mut self, mut it: I) -> <I as Iterator>::Item
        where I: Iterator
    {
        for i in it {
            if self.guess() {
                return i;
            }
        }
        self.fail();
    }
}

fn factor(n: u32) -> (u32, u32) {
    let mut bt = Backtrack::new();
    let i = bt.guess_from(2..100);
    let j = bt.guess_from(2..100);

    if i*j != n {
        bt.fail();
    }

    (i, j)
}

fn factor_391() {
    const N: u32 = 391;
    let (i, j) = factor(N);
    println!("{} * {} = {}\n", i, j, N);

    assert!(i != 1);
    assert!(j != 1);
    assert_eq!(i * j, N);
}

fn solve_maze() {
    const MAZE_SIZE: i32 = 15;

    let mut maze = "\
        X ------------+\n\
        |       |     |\n\
        |--+  | |   | |\n\
        |  |  | | --+ |\n\
        |     |     | |\n\
        |-+---+--+- | |\n\
        | |      |    |\n\
        | | | ---+-+- |\n\
        |   |      |  |\n\
        | +-+-+--|    |\n\
        | |   |  |--- |\n\
        |     |       |\n\
        |--- -+-------|\n\
        |              \n\
        +------------- \n".to_owned().into_bytes();

    let mut bt = Backtrack::new();
    let mut x = 0;
    let mut y = 0;

    while (x != MAZE_SIZE-1) || (y != MAZE_SIZE-1) {
             if bt.guess() { x += 1; }
        else if bt.guess() { x -= 1; }
        else if bt.guess() { y += 1; }
        else               { y -= 1; }

        if (x < 0) || (x >= MAZE_SIZE) || (y < 0) || (y >= MAZE_SIZE) {
            bt.fail();
        }

        let i = (y*(MAZE_SIZE+1) + x) as usize;
        if maze[i] != b' ' {
            bt.fail();
        }

        maze[i] = b'X';
    }

    for c in String::from_utf8(maze).unwrap().chars() {
        if c == 'X' {
            print!("\x1B[1;32mX\x1B[0m");
        } else {
            print!("{}", c);
        }
    }
}

fn main() {
    factor_391();
    solve_maze();
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate core;

#[cfg(test)]
mod tests {
    use core::any::Any;

    // pub trait Any: Reflect + 'static {
    //     /// Gets the `TypeId` of `self`.
    //     #[unstable(feature = "core",
    //                reason = "this method will likely be replaced by an associated static")]
    //     fn get_type_id(&self) -> TypeId;
    // }
    //
    // impl<T: Reflect + 'static> Any for T {
    //     fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
    // }

    // impl Any {
    //     /// Returns true if the boxed type is the same as `T`
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn is<T: Any>(&self) -> bool {
    //         // Get TypeId of the type this function is instantiated with
    //         let t = TypeId::of::<T>();
    //
    //         // Get TypeId of the type in the trait object
    //         let boxed = self.get_type_id();
    //
    //         // Compare both TypeIds on equality
    //         t == boxed
    //     }
    //
    //     /// Returns some reference to the boxed value if it is of type `T`, or
    //     /// `None` if it isn't.
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
    //         if self.is::<T>() {
    //             unsafe {
    //                 // Get the raw representation of the trait object
    //                 let to: TraitObject = transmute(self);
    //
    //                 // Extract the data pointer
    //                 Some(transmute(to.data))
    //             }
    //         } else {
    //             None
    //         }
    //     }
    //
    //     /// Returns some mutable reference to the boxed value if it is of type `T`, or
    //     /// `None` if it isn't.
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
    //         if self.is::<T>() {
    //             unsafe {
    //                 // Get the raw representation of the trait object
    //                 let to: TraitObject = transmute(self);
    //
    //                 // Extract the data pointer
    //                 Some(transmute(to.data))
    //             }
    //         } else {
    //             None
    //         }
    //     }
    // }

    type T = i32;

    #[test]
    fn downcast_mut_test1() {
	let mut x: T = 68;

	{
	    let any: &mut Any = &mut x;
	    let downcast_mut: Option<&mut T> = any.downcast_mut::<T>();

	    match downcast_mut {
		Some(v) => *v = 500,
		None => assert!(false)
	    }
	}

	assert_eq!(x, 500);
    }

    #[test]
    fn downcast_mut_test2() {
	struct A;

	let mut x: T = 68;
	let any: &mut Any = &mut x;
	let downcast_mut: Option<&mut A> = any.downcast_mut::<A>();

	match downcast_mut {
	    Some(_) => assert!(false),
	    None => assert!(true)
	}
    }

}
<commit_msg>remove redundant newline<commit_after>#![feature(core)]
extern crate core;

#[cfg(test)]
mod tests {
    use core::any::Any;

    // pub trait Any: Reflect + 'static {
    //     /// Gets the `TypeId` of `self`.
    //     #[unstable(feature = "core",
    //                reason = "this method will likely be replaced by an associated static")]
    //     fn get_type_id(&self) -> TypeId;
    // }
    //
    // impl<T: Reflect + 'static> Any for T {
    //     fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
    // }

    // impl Any {
    //     /// Returns true if the boxed type is the same as `T`
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn is<T: Any>(&self) -> bool {
    //         // Get TypeId of the type this function is instantiated with
    //         let t = TypeId::of::<T>();
    //
    //         // Get TypeId of the type in the trait object
    //         let boxed = self.get_type_id();
    //
    //         // Compare both TypeIds on equality
    //         t == boxed
    //     }
    //
    //     /// Returns some reference to the boxed value if it is of type `T`, or
    //     /// `None` if it isn't.
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
    //         if self.is::<T>() {
    //             unsafe {
    //                 // Get the raw representation of the trait object
    //                 let to: TraitObject = transmute(self);
    //
    //                 // Extract the data pointer
    //                 Some(transmute(to.data))
    //             }
    //         } else {
    //             None
    //         }
    //     }
    //
    //     /// Returns some mutable reference to the boxed value if it is of type `T`, or
    //     /// `None` if it isn't.
    //     #[stable(feature = "rust1", since = "1.0.0")]
    //     #[inline]
    //     pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
    //         if self.is::<T>() {
    //             unsafe {
    //                 // Get the raw representation of the trait object
    //                 let to: TraitObject = transmute(self);
    //
    //                 // Extract the data pointer
    //                 Some(transmute(to.data))
    //             }
    //         } else {
    //             None
    //         }
    //     }
    // }

    type T = i32;

    #[test]
    fn downcast_mut_test1() {
	let mut x: T = 68;

	{
	    let any: &mut Any = &mut x;
	    let downcast_mut: Option<&mut T> = any.downcast_mut::<T>();

	    match downcast_mut {
		Some(v) => *v = 500,
		None => assert!(false)
	    }
	}

	assert_eq!(x, 500);
    }

    #[test]
    fn downcast_mut_test2() {
	struct A;

	let mut x: T = 68;
	let any: &mut Any = &mut x;
	let downcast_mut: Option<&mut A> = any.downcast_mut::<A>();

	match downcast_mut {
	    Some(_) => assert!(false),
	    None => assert!(true)
	}
    }
}
<|endoftext|>