<commit_before>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

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

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

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

use std::collections::HashMap;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId};
use student::Student;

pub struct Time(u32);

pub struct Cornell {
    locations: HashMap<LocationId, Location>,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            locations: HashMap::new(),

            time: Time(0),
        }
    }

    pub fn addLocation(&mut self, location: Location) {
        self.locations.insert(location.id, location);
    }

    pub fn addStudent(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.locations.get_mut(&location) {
            loc.students.push(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        let mut rng = rand::thread_rng();
        for (location_id, location) in self.locations.iter_mut() {
            for student in location.students.iter_mut() {
                let possible_interactions = interactions.search(&student, *location_id);

                if let Some(interaction) = rng.choose(&possible_interactions) {
                    if let Some(choice) = rng.choose(&interaction.choices) {
                        for effect in choice.effects.iter() {
                            effect.apply(student);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>feat(School): return location ID when adding location<commit_after>/* Copyright 2017 David Li.

 * This file is part of BigRedRPG.

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

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

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

use std::collections::HashMap;

use rand::{self, Rng};

use interactiondb::InteractionDb;
use location::{Location, LocationId};
use student::Student;

pub struct Time(u32);

pub struct Cornell {
    locations: HashMap<LocationId, Location>,

    time: Time,
}

impl Cornell {
    pub fn new() -> Cornell {
        Cornell {
            locations: HashMap::new(),

            time: Time(0),
        }
    }

    pub fn addLocation(&mut self, location: Location) -> LocationId {
        let id = location.id;
        self.locations.insert(location.id, location);

        id
    }

    pub fn addStudent(&mut self, student: Student, location: LocationId) {
        if let Some(loc) = self.locations.get_mut(&location) {
            loc.students.push(student);
        }
        else {
            panic!("LocationId not found: {:?}", location);
        }
    }

    pub fn step(&mut self, interactions: &InteractionDb) {
        let mut rng = rand::thread_rng();
        for (location_id, location) in self.locations.iter_mut() {
            for student in location.students.iter_mut() {
                let possible_interactions = interactions.search(&student, *location_id);

                if let Some(interaction) = rng.choose(&possible_interactions) {
                    if let Some(choice) = rng.choose(&interaction.choices) {
                        for effect in choice.effects.iter() {
                            effect.apply(student);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Unix specific definitions
use std;
use std::io::{self, Read, Write};
use std::sync;
use std::sync::atomic;
use libc;
use nix;
use nix::poll;
use nix::sys::signal;
use nix::sys::termios;

use char_iter;
use consts::{self, KeyPress};
use ::Result;
use ::error;
use super::{RawMode, RawReader, Term};

const STDIN_FILENO: libc::c_int = libc::STDIN_FILENO;
const STDOUT_FILENO: libc::c_int = libc::STDOUT_FILENO;

/// Unsupported Terminals that don't support RAW mode
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
const TIOCGWINSZ: libc::c_ulong = 0x40087468;

#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "android"))]
const TIOCGWINSZ: libc::c_ulong = 0x5413;

#[cfg(all(target_os = "linux", target_env = "musl"))]
const TIOCGWINSZ: libc::c_int = 0x5413;

fn get_win_size() -> (usize, usize) {
    use std::mem::zeroed;
    use libc::c_ushort;

    unsafe {
        #[repr(C)]
        struct winsize {
            ws_row: c_ushort,
            ws_col: c_ushort,
            ws_xpixel: c_ushort,
            ws_ypixel: c_ushort,
        }

        let mut size: winsize = zeroed();
        match libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size) {
            0 => (size.ws_col as usize, size.ws_row as usize), // TODO getCursorPosition
            _ => (80, 24),
        }
    }
}

/// Check TERM environment variable to see if current term is in our
/// unsupported list
fn is_unsupported_term() -> bool {
    use std::ascii::AsciiExt;
    match std::env::var("TERM") {
        Ok(term) => {
            for iter in &UNSUPPORTED_TERM {
                if (*iter).eq_ignore_ascii_case(&term) {
                    return true;
                }
            }
            false
        }
        Err(_) => false,
    }
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
fn is_a_tty(fd: libc::c_int) -> bool {
    unsafe { libc::isatty(fd) != 0 }
}

pub type Mode = termios::Termios;

impl RawMode for Mode {
    /// Disable RAW mode for the terminal.
    fn disable_raw_mode(&self) -> Result<()> {
        try!(termios::tcsetattr(STDIN_FILENO, termios::TCSADRAIN, self));
        Ok(())
    }
}

// Rust std::io::Stdin is buffered with no way to know if bytes are available.
// So we use low-level stuff instead...
struct StdinRaw {}

impl Read for StdinRaw {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        loop {
            let res = unsafe {
                libc::read(STDIN_FILENO,
                           buf.as_mut_ptr() as *mut libc::c_void,
                           buf.len() as libc::size_t)
            };
            if res == -1 {
                let error = io::Error::last_os_error();
                if error.kind() != io::ErrorKind::Interrupted {
                    return Err(error);
                }
            } else {
                return Ok(res as usize);
            }
        }
    }
}

/// Console input reader
pub struct PosixRawReader {
    chars: char_iter::Chars<StdinRaw>,
}

impl PosixRawReader {
    pub fn new() -> Result<PosixRawReader> {
        let stdin = StdinRaw {};
        Ok(PosixRawReader { chars: char_iter::chars(stdin) })
    }

    fn escape_sequence(&mut self) -> Result<KeyPress> {
        // Read the next two bytes representing the escape sequence.
        let seq1 = try!(self.next_char());
        if seq1 == '[' {
            // ESC [ sequences.
            let seq2 = try!(self.next_char());
            if seq2.is_digit(10) {
                // Extended escape, read additional byte.
                let seq3 = try!(self.next_char());
                if seq3 == '~' {
                    match seq2 {
                        // '1' => Ok(KeyPress::Home),
                        '3' => Ok(KeyPress::Delete),
                        // '4' => Ok(KeyPress::End),
                        '5' => Ok(KeyPress::PageUp),
                        '6' => Ok(KeyPress::PageDown),
                        '7' => Ok(KeyPress::Home),
                        '8' => Ok(KeyPress::End),
                        _ => Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    Ok(KeyPress::UnknownEscSeq)
                }
            } else {
                match seq2 {
                    'A' => Ok(KeyPress::Up), // ANSI
                    'B' => Ok(KeyPress::Down),
                    'C' => Ok(KeyPress::Right),
                    'D' => Ok(KeyPress::Left),
                    'F' => Ok(KeyPress::End),
                    'H' => Ok(KeyPress::Home),
                    _ => Ok(KeyPress::UnknownEscSeq),
                }
            }
        } else if seq1 == 'O' {
            // ESC O sequences.
            let seq2 = try!(self.next_char());
            match seq2 {
                'A' => Ok(KeyPress::Up),
                'B' => Ok(KeyPress::Down),
                'C' => Ok(KeyPress::Right),
                'D' => Ok(KeyPress::Left),
                'F' => Ok(KeyPress::End),
                'H' => Ok(KeyPress::Home),
                _ => Ok(KeyPress::UnknownEscSeq),
            }
        } else {
            // TODO ESC-N (n): search history forward not interactively
            // TODO ESC-P (p): search history backward not interactively
            // TODO ESC-R (r): Undo all changes made to this line.
            match seq1 {
                '\x08' => Ok(KeyPress::Meta('\x08')), // Backspace
                '<' => Ok(KeyPress::Meta('<')),
                '>' => Ok(KeyPress::Meta('>')),
                'b' | 'B' => Ok(KeyPress::Meta('B')),
                'c' | 'C' => Ok(KeyPress::Meta('C')),
                'd' | 'D' => Ok(KeyPress::Meta('D')),
                'f' | 'F' => Ok(KeyPress::Meta('F')),
                'l' | 'L' => Ok(KeyPress::Meta('L')),
                't' | 'T' => Ok(KeyPress::Meta('T')),
                'u' | 'U' => Ok(KeyPress::Meta('U')),
                'y' | 'Y' => Ok(KeyPress::Meta('Y')),
                '\x7f' => Ok(KeyPress::Meta('\x7f')), // Delete
                _ => {
                    // writeln!(io::stderr(), "key: {:?}, seq1: {:?}", KeyPress::Esc, seq1).unwrap();
                    Ok(KeyPress::UnknownEscSeq)
                }
            }
        }
    }
}

impl RawReader for PosixRawReader {
    fn next_key(&mut self, timeout_ms: i32) -> Result<KeyPress> {
        let c = try!(self.next_char());

        let mut key = consts::char_to_key_press(c);
        if key == KeyPress::Esc {
            let mut fds =
                [poll::PollFd::new(STDIN_FILENO, poll::POLLIN, poll::EventFlags::empty())];
            match poll::poll(&mut fds, timeout_ms) {
                Ok(n) if n == 0 => {
                    // single escape
                }
                Ok(_) => {
                    // escape sequence
                    key = try!(self.escape_sequence())
                }
                // Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e.into()),
            }
        }
        Ok(key)
    }

    fn next_char(&mut self) -> Result<char> {
        match self.chars.next() {
            Some(c) => Ok(try!(c)),
            None => Err(error::ReadlineError::Eof),
        }
    }
}

static SIGWINCH_ONCE: sync::Once = sync::ONCE_INIT;
static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

fn install_sigwinch_handler() {
    SIGWINCH_ONCE.call_once(|| unsafe {
        let sigwinch = signal::SigAction::new(signal::SigHandler::Handler(sigwinch_handler),
                                              signal::SaFlags::empty(),
                                              signal::SigSet::empty());
        let _ = signal::sigaction(signal::SIGWINCH, &sigwinch);
    });
}

extern "C" fn sigwinch_handler(_: libc::c_int) {
    SIGWINCH.store(true, atomic::Ordering::SeqCst);
}

pub type Terminal = PosixTerminal;

#[derive(Clone,Debug)]
pub struct PosixTerminal {
    unsupported: bool,
    stdin_isatty: bool,
}

impl Term for PosixTerminal {
    type Reader = PosixRawReader;
    type Mode = Mode;

    fn new() -> PosixTerminal {
        let term = PosixTerminal {
            unsupported: is_unsupported_term(),
            stdin_isatty: is_a_tty(STDIN_FILENO),
        };
        if !term.unsupported && term.stdin_isatty && is_a_tty(STDOUT_FILENO) {
            install_sigwinch_handler();
        }
        term
    }

    // Init checks:

    /// Check if current terminal can provide a rich line-editing user interface.
    fn is_unsupported(&self) -> bool {
        self.unsupported
    }

    /// check if stdin is connected to a terminal.
    fn is_stdin_tty(&self) -> bool {
        self.stdin_isatty
    }

    // Interactive loop:

    /// Try to get the number of columns in the current terminal,
    /// or assume 80 if it fails.
    fn get_columns(&self) -> usize {
        let (cols, _) = get_win_size();
        cols
    }

    /// Try to get the number of rows in the current terminal,
    /// or assume 24 if it fails.
    fn get_rows(&self) -> usize {
        let (_, rows) = get_win_size();
        rows
    }

    fn enable_raw_mode(&self) -> Result<Mode> {
        use nix::errno::Errno::ENOTTY;
        use nix::sys::termios::{BRKINT, CS8, ECHO, ICANON, ICRNL, IEXTEN, INPCK, ISIG, ISTRIP,
                                IXON, /* OPOST, */ VMIN, VTIME};
        if !self.stdin_isatty {
            try!(Err(nix::Error::from_errno(ENOTTY)));
        }
        let original_mode = try!(termios::tcgetattr(STDIN_FILENO));
        let mut raw = original_mode;
        // disable BREAK interrupt, CR to NL conversion on input,
        // input parity check, strip high bit (bit 8), output flow control
        raw.c_iflag = raw.c_iflag & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        // we don't want raw output, it turns newlines into straight linefeeds
        // raw.c_oflag = raw.c_oflag & !(OPOST); // disable all output processing
        raw.c_cflag = raw.c_cflag | (CS8); // character-size mark (8 bits)
        // disable echoing, canonical mode, extended input processing and signals
        raw.c_lflag = raw.c_lflag & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1; // One character-at-a-time input
        raw.c_cc[VTIME] = 0; // with blocking read
        try!(termios::tcsetattr(STDIN_FILENO, termios::TCSADRAIN, &raw));
        Ok(original_mode)
    }

    /// Create a RAW reader
    fn create_reader(&self) -> Result<PosixRawReader> {
        PosixRawReader::new()
    }

    /// Check if a SIGWINCH signal has been received
    fn sigwinch(&self) -> bool {
        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, w: &mut Write) -> Result<()> {
        try!(w.write_all(b"\x1b[H\x1b[2J"));
        try!(w.flush());
        Ok(())
    }
}

#[cfg(unix)]
pub fn suspend() -> Result<()> {
    // For macos:
    try!(signal::kill(nix::unistd::getppid(), signal::SIGTSTP));
    try!(signal::kill(nix::unistd::getpid(), signal::SIGTSTP));
    Ok(())
}

#[cfg(all(unix,test))]
mod test {
    #[test]
    fn test_unsupported_term() {
        ::std::env::set_var("TERM", "xterm");
        assert_eq!(false, super::is_unsupported_term());

        ::std::env::set_var("TERM", "dumb");
        assert_eq!(true, super::is_unsupported_term());
    }
}
<commit_msg>Added escape sequence for Home ([1~) and End ([4~) keys for xterm<commit_after>//! Unix specific definitions
use std;
use std::io::{self, Read, Write};
use std::sync;
use std::sync::atomic;
use libc;
use nix;
use nix::poll;
use nix::sys::signal;
use nix::sys::termios;

use char_iter;
use consts::{self, KeyPress};
use ::Result;
use ::error;
use super::{RawMode, RawReader, Term};

const STDIN_FILENO: libc::c_int = libc::STDIN_FILENO;
const STDOUT_FILENO: libc::c_int = libc::STDOUT_FILENO;

/// Unsupported Terminals that don't support RAW mode
static UNSUPPORTED_TERM: [&'static str; 3] = ["dumb", "cons25", "emacs"];

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
const TIOCGWINSZ: libc::c_ulong = 0x40087468;

#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "android"))]
const TIOCGWINSZ: libc::c_ulong = 0x5413;

#[cfg(all(target_os = "linux", target_env = "musl"))]
const TIOCGWINSZ: libc::c_int = 0x5413;

fn get_win_size() -> (usize, usize) {
    use std::mem::zeroed;
    use libc::c_ushort;

    unsafe {
        #[repr(C)]
        struct winsize {
            ws_row: c_ushort,
            ws_col: c_ushort,
            ws_xpixel: c_ushort,
            ws_ypixel: c_ushort,
        }

        let mut size: winsize = zeroed();
        match libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size) {
            0 => (size.ws_col as usize, size.ws_row as usize), // TODO getCursorPosition
            _ => (80, 24),
        }
    }
}

/// Check TERM environment variable to see if current term is in our
/// unsupported list
fn is_unsupported_term() -> bool {
    use std::ascii::AsciiExt;
    match std::env::var("TERM") {
        Ok(term) => {
            for iter in &UNSUPPORTED_TERM {
                if (*iter).eq_ignore_ascii_case(&term) {
                    return true;
                }
            }
            false
        }
        Err(_) => false,
    }
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
fn is_a_tty(fd: libc::c_int) -> bool {
    unsafe { libc::isatty(fd) != 0 }
}

pub type Mode = termios::Termios;

impl RawMode for Mode {
    /// Disable RAW mode for the terminal.
    fn disable_raw_mode(&self) -> Result<()> {
        try!(termios::tcsetattr(STDIN_FILENO, termios::TCSADRAIN, self));
        Ok(())
    }
}

// Rust std::io::Stdin is buffered with no way to know if bytes are available.
// So we use low-level stuff instead...
struct StdinRaw {}

impl Read for StdinRaw {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        loop {
            let res = unsafe {
                libc::read(STDIN_FILENO,
                           buf.as_mut_ptr() as *mut libc::c_void,
                           buf.len() as libc::size_t)
            };
            if res == -1 {
                let error = io::Error::last_os_error();
                if error.kind() != io::ErrorKind::Interrupted {
                    return Err(error);
                }
            } else {
                return Ok(res as usize);
            }
        }
    }
}

/// Console input reader
pub struct PosixRawReader {
    chars: char_iter::Chars<StdinRaw>,
}

impl PosixRawReader {
    pub fn new() -> Result<PosixRawReader> {
        let stdin = StdinRaw {};
        Ok(PosixRawReader { chars: char_iter::chars(stdin) })
    }

    fn escape_sequence(&mut self) -> Result<KeyPress> {
        // Read the next two bytes representing the escape sequence.
        let seq1 = try!(self.next_char());
        if seq1 == '[' {
            // ESC [ sequences.
            let seq2 = try!(self.next_char());
            if seq2.is_digit(10) {
                // Extended escape, read additional byte.
                let seq3 = try!(self.next_char());
                if seq3 == '~' {
                    match seq2 {
                        '1' => Ok(KeyPress::Home), // xterm
                        '3' => Ok(KeyPress::Delete),
                        '4' => Ok(KeyPress::End), // xterm
                        '5' => Ok(KeyPress::PageUp),
                        '6' => Ok(KeyPress::PageDown),
                        '7' => Ok(KeyPress::Home),
                        '8' => Ok(KeyPress::End),
                        _ => Ok(KeyPress::UnknownEscSeq),
                    }
                } else {
                    Ok(KeyPress::UnknownEscSeq)
                }
            } else {
                match seq2 {
                    'A' => Ok(KeyPress::Up), // ANSI
                    'B' => Ok(KeyPress::Down),
                    'C' => Ok(KeyPress::Right),
                    'D' => Ok(KeyPress::Left),
                    'F' => Ok(KeyPress::End),
                    'H' => Ok(KeyPress::Home),
                    _ => Ok(KeyPress::UnknownEscSeq),
                }
            }
        } else if seq1 == 'O' {
            // ESC O sequences.
            let seq2 = try!(self.next_char());
            match seq2 {
                'A' => Ok(KeyPress::Up),
                'B' => Ok(KeyPress::Down),
                'C' => Ok(KeyPress::Right),
                'D' => Ok(KeyPress::Left),
                'F' => Ok(KeyPress::End),
                'H' => Ok(KeyPress::Home),
                _ => Ok(KeyPress::UnknownEscSeq),
            }
        } else {
            // TODO ESC-N (n): search history forward not interactively
            // TODO ESC-P (p): search history backward not interactively
            // TODO ESC-R (r): Undo all changes made to this line.
            match seq1 {
                '\x08' => Ok(KeyPress::Meta('\x08')), // Backspace
                '<' => Ok(KeyPress::Meta('<')),
                '>' => Ok(KeyPress::Meta('>')),
                'b' | 'B' => Ok(KeyPress::Meta('B')),
                'c' | 'C' => Ok(KeyPress::Meta('C')),
                'd' | 'D' => Ok(KeyPress::Meta('D')),
                'f' | 'F' => Ok(KeyPress::Meta('F')),
                'l' | 'L' => Ok(KeyPress::Meta('L')),
                't' | 'T' => Ok(KeyPress::Meta('T')),
                'u' | 'U' => Ok(KeyPress::Meta('U')),
                'y' | 'Y' => Ok(KeyPress::Meta('Y')),
                '\x7f' => Ok(KeyPress::Meta('\x7f')), // Delete
                _ => {
                    // writeln!(io::stderr(), "key: {:?}, seq1: {:?}", KeyPress::Esc, seq1).unwrap();
                    Ok(KeyPress::UnknownEscSeq)
                }
            }
        }
    }
}

impl RawReader for PosixRawReader {
    fn next_key(&mut self, timeout_ms: i32) -> Result<KeyPress> {
        let c = try!(self.next_char());

        let mut key = consts::char_to_key_press(c);
        if key == KeyPress::Esc {
            let mut fds =
                [poll::PollFd::new(STDIN_FILENO, poll::POLLIN, poll::EventFlags::empty())];
            match poll::poll(&mut fds, timeout_ms) {
                Ok(n) if n == 0 => {
                    // single escape
                }
                Ok(_) => {
                    // escape sequence
                    key = try!(self.escape_sequence())
                }
                // Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e.into()),
            }
        }
        Ok(key)
    }

    fn next_char(&mut self) -> Result<char> {
        match self.chars.next() {
            Some(c) => Ok(try!(c)),
            None => Err(error::ReadlineError::Eof),
        }
    }
}

static SIGWINCH_ONCE: sync::Once = sync::ONCE_INIT;
static SIGWINCH: atomic::AtomicBool = atomic::ATOMIC_BOOL_INIT;

fn install_sigwinch_handler() {
    SIGWINCH_ONCE.call_once(|| unsafe {
        let sigwinch = signal::SigAction::new(signal::SigHandler::Handler(sigwinch_handler),
                                              signal::SaFlags::empty(),
                                              signal::SigSet::empty());
        let _ = signal::sigaction(signal::SIGWINCH, &sigwinch);
    });
}

extern "C" fn sigwinch_handler(_: libc::c_int) {
    SIGWINCH.store(true, atomic::Ordering::SeqCst);
}

pub type Terminal = PosixTerminal;

#[derive(Clone,Debug)]
pub struct PosixTerminal {
    unsupported: bool,
    stdin_isatty: bool,
}

impl Term for PosixTerminal {
    type Reader = PosixRawReader;
    type Mode = Mode;

    fn new() -> PosixTerminal {
        let term = PosixTerminal {
            unsupported: is_unsupported_term(),
            stdin_isatty: is_a_tty(STDIN_FILENO),
        };
        if !term.unsupported && term.stdin_isatty && is_a_tty(STDOUT_FILENO) {
            install_sigwinch_handler();
        }
        term
    }

    // Init checks:

    /// Check if current terminal can provide a rich line-editing user interface.
    fn is_unsupported(&self) -> bool {
        self.unsupported
    }

    /// check if stdin is connected to a terminal.
    fn is_stdin_tty(&self) -> bool {
        self.stdin_isatty
    }

    // Interactive loop:

    /// Try to get the number of columns in the current terminal,
    /// or assume 80 if it fails.
    fn get_columns(&self) -> usize {
        let (cols, _) = get_win_size();
        cols
    }

    /// Try to get the number of rows in the current terminal,
    /// or assume 24 if it fails.
    fn get_rows(&self) -> usize {
        let (_, rows) = get_win_size();
        rows
    }

    fn enable_raw_mode(&self) -> Result<Mode> {
        use nix::errno::Errno::ENOTTY;
        use nix::sys::termios::{BRKINT, CS8, ECHO, ICANON, ICRNL, IEXTEN, INPCK, ISIG, ISTRIP,
                                IXON, /* OPOST, */ VMIN, VTIME};
        if !self.stdin_isatty {
            try!(Err(nix::Error::from_errno(ENOTTY)));
        }
        let original_mode = try!(termios::tcgetattr(STDIN_FILENO));
        let mut raw = original_mode;
        // disable BREAK interrupt, CR to NL conversion on input,
        // input parity check, strip high bit (bit 8), output flow control
        raw.c_iflag = raw.c_iflag & !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
        // we don't want raw output, it turns newlines into straight linefeeds
        // raw.c_oflag = raw.c_oflag & !(OPOST); // disable all output processing
        raw.c_cflag = raw.c_cflag | (CS8); // character-size mark (8 bits)
        // disable echoing, canonical mode, extended input processing and signals
        raw.c_lflag = raw.c_lflag & !(ECHO | ICANON | IEXTEN | ISIG);
        raw.c_cc[VMIN] = 1; // One character-at-a-time input
        raw.c_cc[VTIME] = 0; // with blocking read
        try!(termios::tcsetattr(STDIN_FILENO, termios::TCSADRAIN, &raw));
        Ok(original_mode)
    }

    /// Create a RAW reader
    fn create_reader(&self) -> Result<PosixRawReader> {
        PosixRawReader::new()
    }

    /// Check if a SIGWINCH signal has been received
    fn sigwinch(&self) -> bool {
        SIGWINCH.compare_and_swap(true, false, atomic::Ordering::SeqCst)
    }

    /// Clear the screen. Used to handle ctrl+l
    fn clear_screen(&mut self, w: &mut Write) -> Result<()> {
        try!(w.write_all(b"\x1b[H\x1b[2J"));
        try!(w.flush());
        Ok(())
    }
}

#[cfg(unix)]
pub fn suspend() -> Result<()> {
    // For macos:
    try!(signal::kill(nix::unistd::getppid(), signal::SIGTSTP));
    try!(signal::kill(nix::unistd::getpid(), signal::SIGTSTP));
    Ok(())
}

#[cfg(all(unix,test))]
mod test {
    #[test]
    fn test_unsupported_term() {
        ::std::env::set_var("TERM", "xterm");
        assert_eq!(false, super::is_unsupported_term());

        ::std::env::set_var("TERM", "dumb");
        assert_eq!(true, super::is_unsupported_term());
    }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Four_bit_adder
use std::ops::Deref;
use std::fmt;

// primitive gates
fn not(a: bool) -> bool {
    !a
}
fn or(a: bool, b: bool) -> bool {
    a || b
}
fn and(a: bool, b: bool) -> bool {
    a && b
}

/// xor gate [2x not, 2x and, 1x or]
/// (A & !B) | (B & !A)
fn xor(a: bool, b: bool) -> bool {
    or(and(a, not(b)), and(b, not(a)))
}

/// half adder [1x xor, 1x and]
/// S = A ^ B, C = A & B
fn half_adder(a: bool, b: bool) -> (bool, bool) {
    (xor(a, b), and(a, b))
}

/// full adder [2x half_adder, 1x or]
/// t = (C0 + A), t2 = t.S + B
/// S = t2.S, C = t.C | t2.C
fn full_adder(a: bool, b: bool, carry: bool) -> (bool, bool) {
    let (s0, c0) = half_adder(carry, a);
    let (s1, c1) = half_adder(s0, b);

    (s1, or(c0, c1))
}

#[derive(Copy, Clone)]
struct Nibble([bool; 4]);
impl Nibble {
    fn new(arr: [u8; 4]) -> Nibble {
        Nibble([arr[0] != 0, arr[1] != 0, arr[2] != 0, arr[3] != 0])
    }

    fn from_u8(n: u8) -> Nibble {
        Nibble::new([n & 8, n & 4, n & 2, n & 1])
    }

    fn to_u8(&self, carry: bool) -> u8 {
        match u8::from_str_radix(&(format!("{}", self))[..], 2) {
            Ok(n) if carry => n + 16,
            Ok(n) => n,
            Err(_) => unreachable!(),
        }
    }
}

impl fmt::Display for Nibble {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "{}",
               self.iter()
                   .map(|&b| {
                if b {
                    '1'
                } else {
                    '0'
                }
            })
                   .collect::<String>())
    }
}

/// We implement Deref so we can index the Nibble easily
impl<'a> Deref for Nibble {
    type Target = [bool; 4];

    fn deref(&self) -> &[bool; 4] {
        let Nibble(ref inner) = *self;
        inner
    }
}

/// 4bit adder [4x full_adder]
/// calculate each bit of the sum, propogate the carry
fn four_bit_adder(a: Nibble, b: Nibble, carry: bool) -> (Nibble, bool) {
    let (s0, carry) = full_adder(a[3], b[3], carry);
    let (s1, carry) = full_adder(a[2], b[2], carry);
    let (s2, carry) = full_adder(a[1], b[1], carry);
    let (s3, carry) = full_adder(a[0], b[0], carry);

    (Nibble([s3, s2, s1, s0]), carry)
}

fn main() {
    let nib_a = Nibble::new([1u8, 0, 1, 1]);
    let a = nib_a.to_u8(false);
    let b = 6;
    let nib_b = Nibble::from_u8(b);
    let (result, carry) = four_bit_adder(nib_a, nib_b, false);
    println!("{} + {} = {} | {} + {} = {} | overflow: {}",
             a,
             b,
             result.to_u8(carry),
             nib_a,
             nib_b,
             result,
             carry)
}

#[test]
fn test_not() {
    assert_eq!(true, not(false));
    assert_eq!(false, not(true));
}

#[test]
fn test_or() {
    assert_eq!(false, or(false, false));
    assert_eq!(true, or(true, false));
    assert_eq!(true, or(false, true));
    assert_eq!(true, or(true, true));
}

#[test]
fn test_and() {
    assert_eq!(false, and(false, false));
    assert_eq!(false, and(false, true));
    assert_eq!(false, and(true, false));
    assert_eq!(true, and(true, true));
}

#[test]
fn test_xor() {
    assert_eq!(false, xor(false, false));
    assert_eq!(true, xor(false, true));
    assert_eq!(true, xor(true, false));
    assert_eq!(false, xor(true, true));
}

#[test]
fn test_full_add() {
    assert_eq!((false, false), full_adder(false, false, false));
    assert_eq!((true, false), full_adder(false, false, true));
    assert_eq!((true, false), full_adder(false, true, false));
    assert_eq!((true, false), full_adder(true, false, false));
    assert_eq!((false, true), full_adder(false, true, true));
    assert_eq!((false, true), full_adder(true, false, true));
    assert_eq!((false, true), full_adder(true, true, false));
    assert_eq!((true, true), full_adder(true, true, true));
}

#[test]
fn test_four_bit_adder() {
    for (a, b) in (0..std::u8::MAX).map(|n| (n >> 4, n & 15)) {
        let nib_a = Nibble::from_u8(a);
        let nib_b = Nibble::from_u8(b);

        let (result, carry) = four_bit_adder(nib_a, nib_b, false);
        assert_eq!(a + b, result.to_u8(carry));
        let (result, carry) = four_bit_adder(nib_a, nib_b, true);
        assert_eq!(a + b + 1, result.to_u8(carry));
    }
}
<commit_msg>put code/identifiers in backticks in documentation<commit_after>// http://rosettacode.org/wiki/Four_bit_adder
use std::ops::Deref;
use std::fmt;

// primitive gates
fn not(a: bool) -> bool {
    !a
}
fn or(a: bool, b: bool) -> bool {
    a || b
}
fn and(a: bool, b: bool) -> bool {
    a && b
}

/// xor gate [2x not, 2x and, 1x or]
/// (A & !B) | (B & !A)
fn xor(a: bool, b: bool) -> bool {
    or(and(a, not(b)), and(b, not(a)))
}

/// half adder [1x xor, 1x and]
/// S = A ^ B, C = A & B
fn half_adder(a: bool, b: bool) -> (bool, bool) {
    (xor(a, b), and(a, b))
}

/// full adder [2x half adder, 1x or]
/// t = (C0 + A), t2 = t.S + B
/// S = t2.S, C = t.C | t2.C
fn full_adder(a: bool, b: bool, carry: bool) -> (bool, bool) {
    let (s0, c0) = half_adder(carry, a);
    let (s1, c1) = half_adder(s0, b);

    (s1, or(c0, c1))
}

#[derive(Copy, Clone)]
struct Nibble([bool; 4]);
impl Nibble {
    fn new(arr: [u8; 4]) -> Nibble {
        Nibble([arr[0] != 0, arr[1] != 0, arr[2] != 0, arr[3] != 0])
    }

    fn from_u8(n: u8) -> Nibble {
        Nibble::new([n & 8, n & 4, n & 2, n & 1])
    }

    fn to_u8(&self, carry: bool) -> u8 {
        match u8::from_str_radix(&(format!("{}", self))[..], 2) {
            Ok(n) if carry => n + 16,
            Ok(n) => n,
            Err(_) => unreachable!(),
        }
    }
}

impl fmt::Display for Nibble {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f,
               "{}",
               self.iter()
                   .map(|&b| {
                if b {
                    '1'
                } else {
                    '0'
                }
            })
                   .collect::<String>())
    }
}

/// We implement `Deref` so we can index the Nibble easily
impl<'a> Deref for Nibble {
    type Target = [bool; 4];

    fn deref(&self) -> &[bool; 4] {
        let Nibble(ref inner) = *self;
        inner
    }
}

/// 4bit adder [4x full adder]
/// calculate each bit of the sum, propagate the carry
fn four_bit_adder(a: Nibble, b: Nibble, carry: bool) -> (Nibble, bool) {
    let (s0, carry) = full_adder(a[3], b[3], carry);
    let (s1, carry) = full_adder(a[2], b[2], carry);
    let (s2, carry) = full_adder(a[1], b[1], carry);
    let (s3, carry) = full_adder(a[0], b[0], carry);

    (Nibble([s3, s2, s1, s0]), carry)
}

fn main() {
    let nib_a = Nibble::new([1u8, 0, 1, 1]);
    let a = nib_a.to_u8(false);
    let b = 6;
    let nib_b = Nibble::from_u8(b);
    let (result, carry) = four_bit_adder(nib_a, nib_b, false);
    println!("{} + {} = {} | {} + {} = {} | overflow: {}",
             a,
             b,
             result.to_u8(carry),
             nib_a,
             nib_b,
             result,
             carry)
}

#[test]
fn test_not() {
    assert_eq!(true, not(false));
    assert_eq!(false, not(true));
}

#[test]
fn test_or() {
    assert_eq!(false, or(false, false));
    assert_eq!(true, or(true, false));
    assert_eq!(true, or(false, true));
    assert_eq!(true, or(true, true));
}

#[test]
fn test_and() {
    assert_eq!(false, and(false, false));
    assert_eq!(false, and(false, true));
    assert_eq!(false, and(true, false));
    assert_eq!(true, and(true, true));
}

#[test]
fn test_xor() {
    assert_eq!(false, xor(false, false));
    assert_eq!(true, xor(false, true));
    assert_eq!(true, xor(true, false));
    assert_eq!(false, xor(true, true));
}

#[test]
fn test_full_add() {
    assert_eq!((false, false), full_adder(false, false, false));
    assert_eq!((true, false), full_adder(false, false, true));
    assert_eq!((true, false), full_adder(false, true, false));
    assert_eq!((true, false), full_adder(true, false, false));
    assert_eq!((false, true), full_adder(false, true, true));
    assert_eq!((false, true), full_adder(true, false, true));
    assert_eq!((false, true), full_adder(true, true, false));
    assert_eq!((true, true), full_adder(true, true, true));
}

#[test]
fn test_four_bit_adder() {
    for (a, b) in (0..std::u8::MAX).map(|n| (n >> 4, n & 15)) {
        let nib_a = Nibble::from_u8(a);
        let nib_b = Nibble::from_u8(b);

        let (result, carry) = four_bit_adder(nib_a, nib_b, false);
        assert_eq!(a + b, result.to_u8(carry));
        let (result, carry) = four_bit_adder(nib_a, nib_b, true);
        assert_eq!(a + b + 1, result.to_u8(carry));
    }
}
<|endoftext|>


<commit_before>use std::f32::consts::{PI, SQRT2};
use piston::input::{KeyPress, KeyRelease, MouseRelativeMove};
use piston::{GameEvent, Input, Update};
use cam::Camera;

bitflags!(flags Keys: u8 {
    static MoveForward = 0b00000001,
    static MoveBack    = 0b00000010,
    static StrafeLeft  = 0b00000100,
    static StrafeRight = 0b00001000,
    static FlyUp       = 0b00010000,
    static FlyDown     = 0b00100000
})

pub struct FPSController {
    pub yaw: f32,
    pub pitch: f32,
    pub keys: Keys,
    pub direction: [f32, ..3],
    pub velocity: f32,
}

impl FPSController {
    pub fn new() -> FPSController {
        FPSController {
            yaw: 0.0,
            pitch: 0.0,
            keys: Keys::empty(),
            direction: [0.0, 0.0, 0.0],
            velocity: 1.0,
        }
    }

    pub fn event(&mut self, e: &GameEvent, camera: &mut Camera) {
        let &FPSController {
            yaw: ref mut yaw,
            pitch: ref mut pitch,
            keys: ref mut keys,
            direction: ref mut direction,
            velocity: ref mut velocity,
        } = self;

        match *e {
            Update(args) => {
                let dt = args.dt as f32;
                let dh = dt * *velocity * 3.0;
                let [dx, dy, dz] = *direction;
                let (s, c) = (yaw.sin(), yaw.cos());
                camera.position[0] += (s * dx - c * dz) * dh;
                camera.position[1] += dy * dt * 4.0;
                camera.position[2] += (s * dz + c * dx) * dh;
            }
            Input(MouseRelativeMove { dx, dy, .. }) => {
                *yaw = (*yaw - dx as f32 / 360.0 * PI / 4.0) % (2.0 * PI);
                *pitch += dy as f32 / 360.0 * PI / 4.0;
                *pitch = (*pitch).min(PI / 2.0).max(-PI / 2.0);
                camera.set_yaw_pitch(*yaw, *pitch);
            }
            Input(KeyPress { key }) => {
                use piston::input::keyboard::{A, D, S, W, Space, LShift, LCtrl};
                let [dx, dy, dz] = *direction;
                let sgn = |x: f32| if x == 0.0 {0.0} else {x.signum()};
                let set = |k, x: f32, y: f32, z: f32| {
                    let (x, z) = (sgn(x), sgn(z));
                    let (x, z) = if x != 0.0 && z != 0.0 {
                        (x / SQRT2, z / SQRT2)
                    } else {
                        (x, z)
                    };
                    *direction = [x, y, z];
                    keys.insert(k);
                };
                match key {
                    W => set(MoveForward, -1.0, dy, dz),
                    S => set(MoveBack, 1.0, dy, dz),
                    A => set(StrafeLeft, dx, dy, 1.0),
                    D => set(StrafeRight, dx, dy, -1.0),
                    Space => set(FlyUp, dx, 1.0, dz),
                    LShift => set(FlyDown, dx, -1.0, dz),
                    LCtrl => *velocity = 2.0,
                    _ => {}
                }
            }
            Input(KeyRelease { key }) => {
                use piston::input::keyboard::{A, D, S, W, Space, LShift, LCtrl};
                let [dx, dy, dz] = *direction;
                let sgn = |x: f32| if x == 0.0 {0.0} else {x.signum()};
                let set = |x: f32, y: f32, z: f32| {
                    let (x, z) = (sgn(x), sgn(z));
                    let (x, z) = if x != 0.0 && z != 0.0 {
                        (x / SQRT2, z / SQRT2)
                    } else {
                        (x, z)
                    };
                    *direction = [x, y, z];
                };
                let release = |key, rev_key, rev_val| {
                    keys.remove(key);
                    if keys.contains(rev_key) {rev_val} else {0.0}
                };
                match key {
                    W => set(release(MoveForward, MoveBack, 1.0), dy, dz),
                    S => set(release(MoveBack, MoveForward, -1.0), dy, dz),
                    A => set(dx, dy, release(StrafeLeft, StrafeRight, -1.0)),
                    D => set(dx, dy, release(StrafeRight, StrafeLeft, 1.0)),
                    Space => set(dx, release(FlyUp, FlyDown, -1.0), dz),
                    LShift => set(dx, release(FlyDown, FlyUp, 1.0), dz),
                    LCtrl => *velocity = 1.0,
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<commit_msg>Speed up first-person movement.<commit_after>use std::f32::consts::{PI, SQRT2};
use piston::input::{KeyPress, KeyRelease, MouseRelativeMove};
use piston::{GameEvent, Input, Update};
use cam::Camera;

bitflags!(flags Keys: u8 {
    static MoveForward = 0b00000001,
    static MoveBack    = 0b00000010,
    static StrafeLeft  = 0b00000100,
    static StrafeRight = 0b00001000,
    static FlyUp       = 0b00010000,
    static FlyDown     = 0b00100000
})

pub struct FPSController {
    pub yaw: f32,
    pub pitch: f32,
    pub keys: Keys,
    pub direction: [f32, ..3],
    pub velocity: f32,
}

impl FPSController {
    pub fn new() -> FPSController {
        FPSController {
            yaw: 0.0,
            pitch: 0.0,
            keys: Keys::empty(),
            direction: [0.0, 0.0, 0.0],
            velocity: 1.0,
        }
    }

    pub fn event(&mut self, e: &GameEvent, camera: &mut Camera) {
        let &FPSController {
            yaw: ref mut yaw,
            pitch: ref mut pitch,
            keys: ref mut keys,
            direction: ref mut direction,
            velocity: ref mut velocity,
        } = self;

        match *e {
            Update(args) => {
                let dt = args.dt as f32;
                let dh = dt * *velocity * 8.0;
                let [dx, dy, dz] = *direction;
                let (s, c) = (yaw.sin(), yaw.cos());
                camera.position[0] += (s * dx - c * dz) * dh;
                camera.position[1] += dy * dt * 4.0;
                camera.position[2] += (s * dz + c * dx) * dh;
            }
            Input(MouseRelativeMove { dx, dy, .. }) => {
                *yaw = (*yaw - dx as f32 / 360.0 * PI / 4.0) % (2.0 * PI);
                *pitch += dy as f32 / 360.0 * PI / 4.0;
                *pitch = (*pitch).min(PI / 2.0).max(-PI / 2.0);
                camera.set_yaw_pitch(*yaw, *pitch);
            }
            Input(KeyPress { key }) => {
                use piston::input::keyboard::{A, D, S, W, Space, LShift, LCtrl};
                let [dx, dy, dz] = *direction;
                let sgn = |x: f32| if x == 0.0 {0.0} else {x.signum()};
                let set = |k, x: f32, y: f32, z: f32| {
                    let (x, z) = (sgn(x), sgn(z));
                    let (x, z) = if x != 0.0 && z != 0.0 {
                        (x / SQRT2, z / SQRT2)
                    } else {
                        (x, z)
                    };
                    *direction = [x, y, z];
                    keys.insert(k);
                };
                match key {
                    W => set(MoveForward, -1.0, dy, dz),
                    S => set(MoveBack, 1.0, dy, dz),
                    A => set(StrafeLeft, dx, dy, 1.0),
                    D => set(StrafeRight, dx, dy, -1.0),
                    Space => set(FlyUp, dx, 1.0, dz),
                    LShift => set(FlyDown, dx, -1.0, dz),
                    LCtrl => *velocity = 2.0,
                    _ => {}
                }
            }
            Input(KeyRelease { key }) => {
                use piston::input::keyboard::{A, D, S, W, Space, LShift, LCtrl};
                let [dx, dy, dz] = *direction;
                let sgn = |x: f32| if x == 0.0 {0.0} else {x.signum()};
                let set = |x: f32, y: f32, z: f32| {
                    let (x, z) = (sgn(x), sgn(z));
                    let (x, z) = if x != 0.0 && z != 0.0 {
                        (x / SQRT2, z / SQRT2)
                    } else {
                        (x, z)
                    };
                    *direction = [x, y, z];
                };
                let release = |key, rev_key, rev_val| {
                    keys.remove(key);
                    if keys.contains(rev_key) {rev_val} else {0.0}
                };
                match key {
                    W => set(release(MoveForward, MoveBack, 1.0), dy, dz),
                    S => set(release(MoveBack, MoveForward, -1.0), dy, dz),
                    A => set(dx, dy, release(StrafeLeft, StrafeRight, -1.0)),
                    D => set(dx, dy, release(StrafeRight, StrafeLeft, 1.0)),
                    Space => set(dx, release(FlyUp, FlyDown, -1.0), dz),
                    LShift => set(dx, release(FlyDown, FlyUp, 1.0), dz),
                    LCtrl => *velocity = 1.0,
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    young_refs_set: HashSet<Address>,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            young_refs_set: HashSet::new(),
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.old.used_region().size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        self.old.free.store(self.old_top.to_usize(), Ordering::SeqCst);
        let new_size = self.old.used_region().size();

        timer.stop_with(|dur| {
            println!("GC: Full GC ({} ms, {} -> {} size)", in_ms(dur), init_size, new_size);
        });
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        let mut fwd = self.old.total.start;

        while scan < end {
            let obj = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let obj_size = obj.size();

            if self.is_marked(obj) {
                self.fwd_table.insert(scan, fwd);
                fwd = fwd.offset(obj_size);
            }

            scan = scan.offset(obj_size);
        }

        self.old_top = fwd;
    }

    fn update_references(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let mut young_refs = true;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if self.old.contains(field_addr) {
                        let fwd_addr = self.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());

                    } else if self.young.contains(field_addr) {
                        young_refs = true;
                    }
                });

                if young_refs {
                    self.young_refs_set.insert(scan);
                }
            }

            scan = scan.offset(object_size);
        }

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.old.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let &dest = self.fwd_table.get(&scan).expect("forwarding address not found.");
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = self.young_refs_set.contains(&scan);
                }

                let next = dest.offset(object_size);

                if on_different_cards(dest, next) {
                    self.update_crossing(next);
                    self.update_card(scan, &mut young_refs);
                }
            }

            scan = scan.offset(object_size);
        }

        if !start_of_card(scan) {
            self.update_card(scan, &mut young_refs);
        }
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

fn start_of_card(addr: Address) -> bool {
    (addr.to_usize() & (CARD_SIZE - 1)) == addr.to_usize()
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<commit_msg>swiper: Full GC sets right card table entry<commit_after>use std::collections::{HashMap, HashSet};
use std::sync::atomic::Ordering;

use ctxt::SemContext;
use gc::Address;
use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::{CARD_SIZE, CARD_SIZE_BITS};
use gc::swiper::crossing::CrossingMap;
use gc::swiper::old::OldGen;
use gc::swiper::Region;
use gc::swiper::young::YoungGen;
use mem;
use object::Obj;
use os;
use timer::{in_ms, Timer};

pub struct FullCollector<'a, 'ast: 'a> {
    ctxt: &'a SemContext<'ast>,
    heap: Region,
    young: &'a YoungGen,
    old: &'a OldGen,
    rootset: &'a [IndirectObj],
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    perm_space: &'a Space,

    marking_bitmap: MarkingBitmap,
    fwd_table: HashMap<Address, Address>,
    young_refs_set: HashSet<Address>,
    old_top: Address,
}

impl<'a, 'ast> FullCollector<'a, 'ast> {
    pub fn new(
        ctxt: &'a SemContext<'ast>,
        heap: Region,
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        perm_space: &'a Space,
        rootset: &'a [IndirectObj],
    ) -> FullCollector<'a, 'ast> {
        let marking_bitmap = MarkingBitmap::new(heap.clone());

        FullCollector {
            ctxt: ctxt,
            heap: heap,
            young: young,
            old: old,
            rootset: rootset,
            card_table: card_table,
            crossing_map: crossing_map,
            perm_space: perm_space,

            marking_bitmap: marking_bitmap,
            fwd_table: HashMap::new(),
            young_refs_set: HashSet::new(),
            old_top: Address::null(),
        }
    }

    pub fn collect(&mut self) {
        let mut timer = Timer::new(self.ctxt.args.flag_gc_verbose);
        let init_size = self.old.used_region().size();

        self.mark_live();
        self.compute_forward();
        self.update_references();
        self.relocate();

        self.old.free.store(self.old_top.to_usize(), Ordering::SeqCst);
        let new_size = self.old.used_region().size();

        timer.stop_with(|dur| {
            println!("GC: Full GC ({} ms, {} -> {} size)", in_ms(dur), init_size, new_size);
        });
    }

    fn mark_live(&mut self) {
        let mut marking_stack: Vec<Address> = Vec::new();

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.heap.contains(root_ptr) {
                marking_stack.push(root_ptr);

            } else {
                debug_assert!(root_ptr.is_null() || self.perm_space.contains(root_ptr));
            }
        }

        while marking_stack.len() > 0 {
            let object_addr = marking_stack.pop().expect("stack already empty");
            let object = unsafe { &mut *object_addr.to_mut_ptr::<Obj>() };
            self.mark(object_addr);

            object.visit_reference_fields(|field| {
                let field_addr = Address::from_ptr(field.get());

                if self.heap.contains(field_addr) {
                    if !self.is_marked_addr(field_addr) {
                        marking_stack.push(field_addr);
                        self.mark(field_addr);
                    }

                } else {
                    debug_assert!(field_addr.is_null() || self.perm_space.contains(field_addr));
                }
            });
        }
    }

    fn compute_forward(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        let mut fwd = self.old.total.start;

        while scan < end {
            let obj = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let obj_size = obj.size();

            if self.is_marked(obj) {
                self.fwd_table.insert(scan, fwd);
                fwd = fwd.offset(obj_size);
            }

            scan = scan.offset(obj_size);
        }

        self.old_top = fwd;
    }

    fn update_references(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let mut young_refs = false;

                object.visit_reference_fields(|field| {
                    let field_addr = Address::from_ptr(field.get());

                    if self.old.contains(field_addr) {
                        let fwd_addr = self.fwd_table.get(&field_addr).expect("forwarding address not found.");
                        field.set(fwd_addr.to_mut_ptr());

                    } else if self.young.contains(field_addr) {
                        young_refs = true;
                    }
                });

                if young_refs {
                    self.young_refs_set.insert(scan);
                }
            }

            scan = scan.offset(object_size);
        }

        for root in self.rootset {
            let root_ptr = Address::from_ptr(root.get());

            if self.old.contains(root_ptr) {
                let fwd_addr = self.fwd_table.get(&root_ptr).expect("forwarding address not found.");
                root.set(fwd_addr.to_mut_ptr());
            }
        }
    }

    fn relocate(&mut self) {
        let used_region = self.old.used_region();

        let mut scan = used_region.start;
        let end = used_region.end;

        self.crossing_map.set_first_object(0.into(), 0);
        let mut young_refs = false;
        let mut last_dest = Address::null();

        while scan < end {
            let object = unsafe { &mut *scan.to_mut_ptr::<Obj>() };
            let object_size = object.size();

            if self.is_marked(object) {
                let &dest = self.fwd_table.get(&scan).expect("forwarding address not found.");
                object.copy_to(dest, object_size);

                if !young_refs {
                    young_refs = self.young_refs_set.contains(&scan);
                }

                let next_dest = dest.offset(object_size);

                if on_different_cards(dest, next_dest) {
                    self.update_crossing(next_dest);
                    self.update_card(dest, &mut young_refs);
                }

                last_dest = next_dest;
            }

            scan = scan.offset(object_size);
        }

        if !last_dest.is_null() && !start_of_card(last_dest) {
            self.update_card(last_dest, &mut young_refs);
        }
    }

    fn update_crossing(&mut self, addr: Address) {
        let offset = addr.to_usize() & (CARD_SIZE - 1);
        let offset_words = offset / (mem::ptr_width() as usize);

        let card = self.old.card_from_address(addr);

        self.crossing_map.set_first_object(card, offset_words);
    }

    fn update_card(&mut self, addr: Address, young_refs: &mut bool) {
        let card = self.old.card_from_address(addr);

        let card_entry = if *young_refs { CardEntry::Dirty } else { CardEntry:: Clean };
        self.card_table.set(card, card_entry);

        *young_refs = false;
    }

    fn is_marked(&self, obj: &Obj) -> bool {
        self.marking_bitmap.is_marked(Address::from_ptr(obj as *const _))
    }

    fn is_marked_addr(&self, addr: Address) -> bool {
        self.marking_bitmap.is_marked(addr)
    }

    fn mark(&mut self, addr: Address) {
        self.marking_bitmap.mark(addr);
    }
}

fn on_different_cards(curr: Address, next: Address) -> bool {
    (curr.to_usize() >> CARD_SIZE_BITS) != (next.to_usize() >> CARD_SIZE_BITS)
}

fn start_of_card(addr: Address) -> bool {
    (addr.to_usize() & (CARD_SIZE - 1)) == addr.to_usize()
}

pub struct MarkingBitmap {
    heap: Region,
    bitmap: Region,
}

impl MarkingBitmap {
    pub fn new(heap: Region) -> MarkingBitmap {
        let bitmap_size = mem::page_align(heap.size() / mem::ptr_width_usize() / 8);
        let bitmap_start = Address::from_ptr(os::mmap(bitmap_size, os::Writable));

        if bitmap_start.is_null() {
            panic!("could not allocate marking bitmap.");
        }

        MarkingBitmap {
            heap: heap,
            bitmap: Region::new(bitmap_start, bitmap_start.offset(bitmap_size)),
        }
    }

    pub fn mark(&mut self, addr: Address) {
        let (byte_offset, bit_offset) = self.mark_offset(addr);

        let byte = self.mark_byte(byte_offset);
        let modified_byte = byte | (1 << bit_offset);
        self.set_mark_byte(byte_offset, modified_byte);
    }

    pub fn is_marked(&self, addr: Address) -> bool {
        let (byte_offset, bit_offset) = self.mark_offset(addr);
        let byte = self.mark_byte(byte_offset);

        byte & (1 << bit_offset) != 0
    }

    fn mark_offset(&self, addr: Address) -> (usize, u8) {
        debug_assert!(self.heap.contains(addr));
        let offset = addr.offset_from(self.heap.start) / mem::ptr_width_usize();
        let byte = offset / 8;
        let bit = offset % 8;

        (byte, bit as u8)
    }

    fn mark_byte(&self, offset: usize) -> u8 {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_ptr()
        }
    }

    fn set_mark_byte(&self, offset: usize, val: u8) {
        let addr = self.bitmap.start.offset(offset);

        unsafe {
            *addr.to_mut_ptr() = val;
        }
    }
}

impl Drop for MarkingBitmap {
    fn drop(&mut self) {
        os::munmap(self.bitmap.start.to_ptr(), self.bitmap.size());
    }
}<|endoftext|>


<commit_before>use std::sync::Arc;

use collect_slice::CollectSlice;
use crossbeam;
use rand;

use coefs::Coefficients;
use consts::SAMPLES_PER_FRAME;
use descramble::{descramble, Bootstrap};
use enhance::{self, EnhancedSpectrals, FrameEnergy, EnhanceErrors};
use frame::{AudioBuf, ReceivedFrame};
use gain::Gains;
use params::BaseParams;
use prev::PrevFrame;
use spectral::Spectrals;
use unvoiced::{UnvoicedDFT, Unvoiced};
use voiced::{Phase, PhaseBase, Voiced};

/// Number of threads to spin up per frame.
const THREADS: usize = 4;
/// Number of samples to process in each thread.
const SAMPLES_PER_THREAD: usize = SAMPLES_PER_FRAME / THREADS;

pub struct IMBEDecoder {
    prev: PrevFrame,
}

impl IMBEDecoder {
    pub fn new() -> IMBEDecoder {
        IMBEDecoder {
            prev: PrevFrame::default(),
        }
    }

    pub fn decode(&mut self, frame: ReceivedFrame, buf: &mut AudioBuf) {
        let period = match Bootstrap::new(&frame.chunks) {
            Bootstrap::Period(p) => p,
            Bootstrap::Invalid => {
                self.repeat(buf);
                return;
            },
            Bootstrap::Silence => {
                self.silence(buf);
                return;
            },
        };

        let errors = EnhanceErrors::new(&frame.errors, self.prev.err_rate);

        if enhance::should_repeat(&errors) {
            self.repeat(buf);
            return;
        }

        if enhance::should_mute(&errors) {
            self.silence(buf);
            return;
        }

        let params = BaseParams::new(period);
        let (amps, mut voice, gain_idx) = descramble(&frame.chunks, &params);
        let gains = Gains::new(gain_idx, &amps, &params);
        let coefs = Coefficients::new(&gains, &amps, &params);
        let spectrals = Spectrals::new(&coefs, &params, &self.prev);
        let energy = FrameEnergy::new(&spectrals, &self.prev.energy, &params);

        let mut enhanced = EnhancedSpectrals::new(&spectrals, &energy, &params);
        let amp_thresh = enhance::amp_thresh(&errors, self.prev.amp_thresh);
        enhance::smooth(&mut enhanced, &mut voice, &errors, &energy, amp_thresh);

        let udft = UnvoicedDFT::new(&params, &voice, &enhanced, rand::weak_rng());
        let vbase = PhaseBase::new(&params, &self.prev);
        let vphase = Phase::new(&vbase, &params, &self.prev, &voice, rand::weak_rng());

        crossbeam::scope(|scope| {
            let unvoiced = Arc::new(Unvoiced::new(&udft, &self.prev.unvoiced));
            let voiced = Arc::new(Voiced::new(&params, &self.prev, &vphase, &enhanced, &voice));

            for (i, chunk) in buf.chunks_mut(SAMPLES_PER_THREAD).enumerate() {
                let u = unvoiced.clone();
                let v = voiced.clone();

                let start = i * SAMPLES_PER_THREAD;
                let stop = start + SAMPLES_PER_THREAD;

                scope.spawn(move || {
                    (start..stop)
                        .map(|n| u.get(n) + v.get(n))
                        .collect_slice(&mut chunk[..]);
                });
            }
        });

        self.prev = PrevFrame {
            params: params,
            spectrals: spectrals,
            enhanced: enhanced,
            voice: voice,
            err_rate: errors.rate,
            energy: energy,
            amp_thresh: amp_thresh,
            unvoiced: udft,
            phase_base: vbase,
            phase: vphase,
        };
    }

    fn silence(&self, buf: &mut AudioBuf) {
        (0..SAMPLES_PER_FRAME).map(|_| 0.0).collect_slice(&mut buf[..]);
    }

    fn repeat(&self, buf: &mut AudioBuf) {
        let params = self.prev.params.clone();
        let voice = self.prev.voice.clone();
        let enhanced = self.prev.enhanced.clone();

        let udft = UnvoicedDFT::new(&params, &voice, &enhanced, rand::weak_rng());
        let vbase = PhaseBase::new(&params, &self.prev);
        let vphase = Phase::new(&vbase, &params, &self.prev, &voice, rand::weak_rng());

        let unvoiced = Unvoiced::new(&udft, &self.prev.unvoiced);
        let voiced = Voiced::new(&params, &self.prev, &vphase, &enhanced, &voice);

        (0..SAMPLES_PER_FRAME)
            .map(|n| unvoiced.get(n) + voiced.get(n))
            .collect_slice(&mut buf[..]);
    }
}

#[cfg(test)]
mod test {
    use super::THREADS;
    use consts::SAMPLES_PER_FRAME;

    #[test]
    fn verify_threads() {
        assert!(SAMPLES_PER_FRAME % THREADS == 0);
    }
}
<commit_msg>Use collect_slice_checked in decoder module<commit_after>use std::sync::Arc;

use collect_slice::CollectSlice;
use crossbeam;
use rand;

use coefs::Coefficients;
use consts::SAMPLES_PER_FRAME;
use descramble::{descramble, Bootstrap};
use enhance::{self, EnhancedSpectrals, FrameEnergy, EnhanceErrors};
use frame::{AudioBuf, ReceivedFrame};
use gain::Gains;
use params::BaseParams;
use prev::PrevFrame;
use spectral::Spectrals;
use unvoiced::{UnvoicedDFT, Unvoiced};
use voiced::{Phase, PhaseBase, Voiced};

/// Number of threads to spin up per frame.
const THREADS: usize = 4;
/// Number of samples to process in each thread.
const SAMPLES_PER_THREAD: usize = SAMPLES_PER_FRAME / THREADS;

pub struct IMBEDecoder {
    prev: PrevFrame,
}

impl IMBEDecoder {
    pub fn new() -> IMBEDecoder {
        IMBEDecoder {
            prev: PrevFrame::default(),
        }
    }

    pub fn decode(&mut self, frame: ReceivedFrame, buf: &mut AudioBuf) {
        let period = match Bootstrap::new(&frame.chunks) {
            Bootstrap::Period(p) => p,
            Bootstrap::Invalid => {
                self.repeat(buf);
                return;
            },
            Bootstrap::Silence => {
                self.silence(buf);
                return;
            },
        };

        let errors = EnhanceErrors::new(&frame.errors, self.prev.err_rate);

        if enhance::should_repeat(&errors) {
            self.repeat(buf);
            return;
        }

        if enhance::should_mute(&errors) {
            self.silence(buf);
            return;
        }

        let params = BaseParams::new(period);
        let (amps, mut voice, gain_idx) = descramble(&frame.chunks, &params);
        let gains = Gains::new(gain_idx, &amps, &params);
        let coefs = Coefficients::new(&gains, &amps, &params);
        let spectrals = Spectrals::new(&coefs, &params, &self.prev);
        let energy = FrameEnergy::new(&spectrals, &self.prev.energy, &params);

        let mut enhanced = EnhancedSpectrals::new(&spectrals, &energy, &params);
        let amp_thresh = enhance::amp_thresh(&errors, self.prev.amp_thresh);
        enhance::smooth(&mut enhanced, &mut voice, &errors, &energy, amp_thresh);

        let udft = UnvoicedDFT::new(&params, &voice, &enhanced, rand::weak_rng());
        let vbase = PhaseBase::new(&params, &self.prev);
        let vphase = Phase::new(&vbase, &params, &self.prev, &voice, rand::weak_rng());

        crossbeam::scope(|scope| {
            let unvoiced = Arc::new(Unvoiced::new(&udft, &self.prev.unvoiced));
            let voiced = Arc::new(Voiced::new(&params, &self.prev, &vphase, &enhanced, &voice));

            for (i, chunk) in buf.chunks_mut(SAMPLES_PER_THREAD).enumerate() {
                let u = unvoiced.clone();
                let v = voiced.clone();

                let start = i * SAMPLES_PER_THREAD;
                let stop = start + SAMPLES_PER_THREAD;

                scope.spawn(move || {
                    (start..stop)
                        .map(|n| u.get(n) + v.get(n))
                        .collect_slice_checked(&mut chunk[..]);
                });
            }
        });

        self.prev = PrevFrame {
            params: params,
            spectrals: spectrals,
            enhanced: enhanced,
            voice: voice,
            err_rate: errors.rate,
            energy: energy,
            amp_thresh: amp_thresh,
            unvoiced: udft,
            phase_base: vbase,
            phase: vphase,
        };
    }

    fn silence(&self, buf: &mut AudioBuf) {
        (0..SAMPLES_PER_FRAME).map(|_| 0.0).collect_slice_checked(&mut buf[..]);
    }

    fn repeat(&self, buf: &mut AudioBuf) {
        let params = self.prev.params.clone();
        let voice = self.prev.voice.clone();
        let enhanced = self.prev.enhanced.clone();

        let udft = UnvoicedDFT::new(&params, &voice, &enhanced, rand::weak_rng());
        let vbase = PhaseBase::new(&params, &self.prev);
        let vphase = Phase::new(&vbase, &params, &self.prev, &voice, rand::weak_rng());

        let unvoiced = Unvoiced::new(&udft, &self.prev.unvoiced);
        let voiced = Voiced::new(&params, &self.prev, &vphase, &enhanced, &voice);

        (0..SAMPLES_PER_FRAME)
            .map(|n| unvoiced.get(n) + voiced.get(n))
            .collect_slice_checked(&mut buf[..]);
    }
}

#[cfg(test)]
mod test {
    use super::THREADS;
    use consts::SAMPLES_PER_FRAME;

    #[test]
    fn verify_threads() {
        assert!(SAMPLES_PER_FRAME % THREADS == 0);
    }
}
<|endoftext|>


<commit_before>use {types as ot, errors as oe, utils};

use std::io;
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<ot::OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(ot::OscPacket::Message(ot::OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(ot::OscPacket::Message(ot::OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(oe::OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<ot::OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                   .map_err(oe::OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(oe::OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(oe::OscError::BadBundle);
    }

    Ok(ot::OscPacket::Bundle(ot::OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| oe::OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        }
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>,
                 raw_type_tags: String)
                 -> ot::OscResult<Vec<ot::OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<ot::OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            }
            Err(e) => return Err(e),
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> ot::OscResult<ot::OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(|f| ot::OscType::Float(f))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(|d| ot::OscType::Double(d))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(|i| ot::OscType::Int(i))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(|l| ot::OscType::Long(l))
                  .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        's' => {
            read_osc_string(cursor).map(|s| ot::OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(ot::OscType::Blob(buf)),
                        Err(e) => Err(oe::OscError::ReadError(e)),
                    }
                }
                // TODO: use correct error type
                Err(e) => return Err(oe::OscError::BadBundle),
            }
        }
        _ => Err(oe::OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<ot::OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(ot::OscType::Time(date, frac)),
                Err(e) => Err(oe::OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(oe::OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Simplify imports<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscBundle};
use errors::OscError;
use utils;

use std::io;
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                   .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        }
        Err(e) => Err(OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>,
                 raw_type_tags: String)
                 -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            }
            Err(e) => return Err(e),
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(|f| OscType::Float(f))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(|d| OscType::Double(d))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(|i| OscType::Int(i))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(|l| OscType::Long(l))
                  .map_err(|e| OscError::ByteOrderError(e))
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(OscType::Blob(buf)),
                        Err(e) => Err(OscError::ReadError(e)),
                    }
                }
                // TODO: use correct error type
                Err(e) => return Err(OscError::BadBundle),
            }
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::{iter, str};

pub fn encode_packet(packet: OscPacket) -> Result<Vec<u8>> {
    match packet {
        OscPacket::Message(msg) => encode_message(msg),
        OscPacket::Bundle(bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args: Vec<OscType> = msg.args.unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(type_tags.iter()
                                            .cloned()
                                            .collect()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        OscType::Int(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_i32(&mut bytes, x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_i64(&mut bytes, x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_f32(&mut bytes, x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_f64(&mut bytes, x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_u32(&mut bytes, x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(x) => {
            Ok((Some(encode_string(x)), 's'))
        }
        OscType::Blob(x) => {
            let mut bytes = x.clone();
            pad_bytes(&mut bytes);
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(x, y) => {
            Ok((Some(encode_time_tag(x, y)), 't'))
        }
        OscType::Midi(x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Bool(x) => {
            if x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = Vec::with_capacity(8);
    BigEndian::write_u32(&mut bytes[..3], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<commit_msg>Remove unused import<commit_after>use types::{Result, OscType, OscPacket, OscBundle, OscMessage};
use errors::OscError;
use utils;

use byteorder::{ByteOrder, BigEndian};
use std::iter;

pub fn encode_packet(packet: OscPacket) -> Result<Vec<u8>> {
    match packet {
        OscPacket::Message(msg) => encode_message(msg),
        OscPacket::Bundle(bundle) => encode_bundle(bundle),
    }
}

fn encode_message(msg: OscMessage) -> Result<Vec<u8>> {
    let mut msg_bytes: Vec<u8> = Vec::new();

    msg_bytes.extend(encode_string(msg.addr));
    let mut type_tags: Vec<char> = vec![','];
    let mut arg_bytes: Vec<u8> = Vec::new();

    if msg.args.is_some() {
        let args: Vec<OscType> = msg.args.unwrap();
        // Possible optimization: write this as iterator
        for arg in args {
            let (bytes, tag): (Option<Vec<u8>>, char) = try!(encode(arg));

            type_tags.push(tag);
            if bytes.is_some() {
                arg_bytes.extend(bytes.unwrap());
            }
        }
    }

    msg_bytes.extend(encode_string(type_tags.iter()
                                            .cloned()
                                            .collect()));
    if arg_bytes.len() > 0 {
        msg_bytes.extend(arg_bytes);
    }
    Ok(msg_bytes)
}

fn encode_bundle(bundle: OscBundle) -> Result<Vec<u8>> {
    Err(OscError::Unimplemented)
}

fn encode(arg: OscType) -> Result<(Option<Vec<u8>>, char)> {
    match arg {
        OscType::Int(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_i32(&mut bytes, x);
            Ok((Some(bytes), 'i'))
        }
        OscType::Long(x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_i64(&mut bytes, x);
            Ok((Some(bytes), 'h'))
        }
        OscType::Float(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_f32(&mut bytes, x);
            Ok((Some(bytes), 'f'))
        }
        OscType::Double(x) => {
            let mut bytes = Vec::with_capacity(8);
            BigEndian::write_f64(&mut bytes, x);
            Ok((Some(bytes), 'd'))
        }
        OscType::Char(x) => {
            let mut bytes = Vec::with_capacity(4);
            BigEndian::write_u32(&mut bytes, x as u32);
            Ok((Some(bytes), 'c'))
        }
        OscType::String(x) => {
            Ok((Some(encode_string(x)), 's'))
        }
        OscType::Blob(x) => {
            let mut bytes = x.clone();
            pad_bytes(&mut bytes);
            Ok((Some(bytes), 'b'))
        }
        OscType::Time(x, y) => {
            Ok((Some(encode_time_tag(x, y)), 't'))
        }
        OscType::Midi(x) => {
            Ok((Some(vec![x.port, x.status, x.data1, x.data2]), 'm'))
        }
        OscType::Bool(x) => {
            if x {
                Ok((None, 'T'))
            } else {
                Ok((None, 'F'))
            }
        }
        OscType::Nil => {
            Ok((None, 'N'))
        }
        OscType::Inf => {
            Ok((None, 'I'))
        }
        _ => Err(OscError::Unimplemented),
    }
}

fn encode_string(s: String) -> Vec<u8> {
    let mut bytes: Vec<u8> = s.as_bytes()
                              .iter()
                              .cloned()
                              .chain(iter::once(0u8))
                              .collect();
    pad_bytes(&mut bytes);
    bytes
}

fn pad_bytes(bytes: &mut Vec<u8>) {
    let padded_lengh = utils::pad(bytes.len() as u64);
    while bytes.len() < padded_lengh as usize {
        bytes.push(0u8)
    }
}

fn encode_time_tag(sec: u32, frac: u32) -> Vec<u8> {
    let mut bytes = Vec::with_capacity(8);
    BigEndian::write_u32(&mut bytes[..3], sec);
    BigEndian::write_u32(&mut bytes[4..], frac);
    bytes
}
<|endoftext|>