<commit_before>use super::{pointer::Pointer, Heap};
use crate::{
    builtin_functions::BuiltinFunction,
    compiler::{
        hir_to_lir::HirToLir,
        lir::{Instruction, Lir},
    },
    database::Database,
    module::Module,
};
use itertools::Itertools;
use num_bigint::BigInt;
use std::{
    collections::{hash_map::DefaultHasher, HashMap},
    hash::{Hash, Hasher},
    ops::Deref,
};

#[derive(Clone)]
pub struct Object {
    pub reference_count: usize,
    pub data: Data,
}
#[derive(Clone)]
pub enum Data {
    Int(Int),
    Text(Text),
    Symbol(Symbol),
    Struct(Struct),
    Closure(Closure),
    Builtin(Builtin),
}

#[derive(Clone)]
pub struct Int {
    pub value: BigInt,
}

#[derive(Clone)]
pub struct Text {
    pub value: String,
}

#[derive(Clone)]
pub struct Symbol {
    // TODO: Choose a more efficient representation.
    pub value: String,
}

#[derive(Default, Clone)]
pub struct Struct {
    // TODO: Choose a more efficient representation.
    pub buckets: HashMap<u64, Vec<(Pointer, Pointer)>>, // hash -> list of keys and values
}

#[derive(Clone)]
pub struct Closure {
    pub captured: Vec<Pointer>,
    pub num_args: usize,
    pub body: Vec<Instruction>,
}

#[derive(Clone)]
pub struct Builtin {
    pub function: BuiltinFunction,
}

impl Struct {
    pub fn from_fields(heap: &Heap, fields: HashMap<Pointer, Pointer>) -> Self {
        let mut s = Self::default();
        for (key, value) in fields {
            s.insert(heap, key, value);
        }
        s
    }
    fn insert(&mut self, heap: &Heap, key: Pointer, value: Pointer) {
        let bucket = self.buckets.entry(key.hash(heap)).or_default();
        for (existing_key, existing_value) in bucket.iter_mut() {
            if existing_key.equals(heap, key) {
                *existing_value = value;
                return;
            }
        }
        bucket.push((key, value));
    }
    pub fn get(&self, heap: &Heap, key: Pointer) -> Option<Pointer> {
        let bucket = self.buckets.get(&key.hash(heap))?;
        for (existing_key, existing_value) in bucket {
            if existing_key.equals(heap, key) {
                return Some(*existing_value);
            }
        }
        None
    }
    fn len(&self) -> usize {
        self.buckets.values().map(|bucket| bucket.len()).sum()
    }
    pub fn iter(&self) -> impl Iterator<Item = (Pointer, Pointer)> {
        self.buckets.clone().into_values().flatten()
    }
    fn equals(&self, heap: &Heap, other: &Struct) -> bool {
        if self.len() != other.len() {
            return false;
        }
        for (key_a, value_a) in self.iter() {
            for (key_b, value_b) in other.iter() {
                if !key_a.equals(heap, key_b) || !value_a.equals(heap, value_b) {
                    return false;
                }
            }
        }
        true
    }
}

impl Closure {
    pub fn of_module_lir(module: Module, lir: Lir) -> Self {
        Closure {
            captured: vec![],
            num_args: 0,
            body: vec![
                Instruction::TraceModuleStarts { module },
                Instruction::CreateClosure {
                    captured: vec![],
                    num_args: 0,
                    body: lir.instructions,
                },
                Instruction::Call { num_args: 0 },
                Instruction::TraceModuleEnds,
                Instruction::Return,
            ],
        }
    }
    pub fn of_module(db: &Database, module: Module) -> Option<Self> {
        let lir = db.lir(module.clone())?;
        Some(Self::of_module_lir(module, (*lir).clone()))
    }
}

impl Data {
    fn hash(&self, heap: &Heap) -> u64 {
        let mut state = DefaultHasher::new();
        self.hash_with_state(heap, &mut state);
        state.finish()
    }

    fn hash_with_state<H: Hasher>(&self, heap: &Heap, state: &mut H) {
        match self {
            Data::Int(int) => int.value.hash(state),
            Data::Text(text) => text.value.hash(state),
            Data::Symbol(symbol) => symbol.value.hash(state),
            Data::Struct(struct_) => {
                let mut s = 0;
                for (key, value) in struct_.iter() {
                    s ^= key.hash(heap);
                    s ^= value.hash(heap);
                }
                s.hash(state)
            }
            Data::Closure(closure) => {
                for captured in &closure.captured {
                    captured.hash_with_state(heap, state);
                }
                closure.num_args.hash(state);
                closure.body.hash(state);
            }
            Data::Builtin(builtin) => builtin.function.hash(state),
        }
    }

    pub fn equals(&self, heap: &Heap, other: &Self) -> bool {
        match (self, other) {
            (Data::Int(a), Data::Int(b)) => a.value == b.value,
            (Data::Text(a), Data::Text(b)) => a.value == b.value,
            (Data::Symbol(a), Data::Symbol(b)) => a.value == b.value,
            (Data::Struct(a), Data::Struct(b)) => a.equals(heap, b),
            (Data::Closure(_), Data::Closure(_)) => false,
            (Data::Builtin(a), Data::Builtin(b)) => a.function == b.function,
            _ => false,
        }
    }

    pub fn format(&self, heap: &Heap) -> String {
        match self {
            Data::Int(int) => format!("{}", int.value),
            Data::Text(text) => format!("\"{}\"", text.value),
            Data::Symbol(symbol) => symbol.value.to_string(),
            Data::Struct(struct_) => format!(
                "[{}]",
                struct_
                    .iter()
                    .map(|(key, value)| (key.format(heap), value.format(heap)))
                    .sorted_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b))
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Data::Closure(_) => "{…}".to_string(),
            Data::Builtin(builtin) => format!("builtin{:?}", builtin.function),
        }
    }

    pub fn children(&self) -> Vec<Pointer> {
        match self {
            Data::Int(_) | Data::Text(_) | Data::Symbol(_) | Data::Builtin(_) => vec![],
            Data::Struct(struct_) => struct_
                .iter()
                .flat_map(|(a, b)| vec![a, b].into_iter())
                .collect_vec(),
            Data::Closure(closure) => closure.captured.clone(),
        }
    }
}

impl Deref for Object {
    type Target = Data;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl Pointer {
    fn hash(&self, heap: &Heap) -> u64 {
        heap.get(*self).hash(heap)
    }
    fn hash_with_state<H: Hasher>(&self, heap: &Heap, state: &mut H) {
        heap.get(*self).hash_with_state(heap, state)
    }
    pub fn equals(&self, heap: &Heap, other: Self) -> bool {
        if *self == other {
            return true;
        }
        heap.get(*self).equals(heap, heap.get(other))
    }
    pub fn format(&self, heap: &Heap) -> String {
        heap.get(*self).format(heap)
    }
}
<commit_msg>Add suggestion<commit_after>use super::{pointer::Pointer, Heap};
use crate::{
    builtin_functions::BuiltinFunction,
    compiler::{
        hir_to_lir::HirToLir,
        lir::{Instruction, Lir},
    },
    database::Database,
    module::Module,
};
use itertools::Itertools;
use num_bigint::BigInt;
use std::{
    collections::{hash_map::DefaultHasher, HashMap},
    hash::{Hash, Hasher},
    ops::Deref,
};

#[derive(Clone)]
pub struct Object {
    pub reference_count: usize,
    pub data: Data,
}
#[derive(Clone)]
pub enum Data {
    Int(Int),
    Text(Text),
    Symbol(Symbol),
    Struct(Struct),
    Closure(Closure),
    Builtin(Builtin),
}

#[derive(Clone)]
pub struct Int {
    pub value: BigInt,
}

#[derive(Clone)]
pub struct Text {
    pub value: String,
}

#[derive(Clone)]
pub struct Symbol {
    // TODO: Choose a more efficient representation.
    pub value: String,
}

#[derive(Default, Clone)]
pub struct Struct {
    // TODO: Choose a more efficient representation.
    pub buckets: HashMap<u64, Vec<(Pointer, Pointer)>>, // hash -> list of keys and values
}

#[derive(Clone)]
pub struct Closure {
    pub captured: Vec<Pointer>,
    pub num_args: usize,
    pub body: Vec<Instruction>,
}

#[derive(Clone)]
pub struct Builtin {
    pub function: BuiltinFunction,
}

impl Struct {
    pub fn from_fields(heap: &Heap, fields: HashMap<Pointer, Pointer>) -> Self {
        let mut s = Self::default();
        for (key, value) in fields {
            s.insert(heap, key, value);
        }
        s
    }
    fn insert(&mut self, heap: &Heap, key: Pointer, value: Pointer) {
        let bucket = self.buckets.entry(key.hash(heap)).or_default();
        for (existing_key, existing_value) in bucket.iter_mut() {
            if existing_key.equals(heap, key) {
                *existing_value = value;
                return;
            }
        }
        bucket.push((key, value));
    }
    pub fn get(&self, heap: &Heap, key: Pointer) -> Option<Pointer> {
        let bucket = self.buckets.get(&key.hash(heap))?;
        for (existing_key, existing_value) in bucket {
            if existing_key.equals(heap, key) {
                return Some(*existing_value);
            }
        }
        None
    }
    fn len(&self) -> usize {
        self.buckets.values().map(|bucket| bucket.len()).sum()
    }
    pub fn iter(&self) -> impl Iterator<Item = (Pointer, Pointer)> {
        self.buckets.clone().into_values().flatten()
    }
    fn equals(&self, heap: &Heap, other: &Struct) -> bool {
        if self.len() != other.len() {
            return false;
        }
        for (key_a, value_a) in self.iter() {
            for (key_b, value_b) in other.iter() {
                if key_a.equals(heap, key_b) && !value_a.equals(heap, value_b) {
                    return false;
                }
            }
        }
        true
    }
}

impl Closure {
    pub fn of_module_lir(module: Module, lir: Lir) -> Self {
        Closure {
            captured: vec![],
            num_args: 0,
            body: vec![
                Instruction::TraceModuleStarts { module },
                Instruction::CreateClosure {
                    captured: vec![],
                    num_args: 0,
                    body: lir.instructions,
                },
                Instruction::Call { num_args: 0 },
                Instruction::TraceModuleEnds,
                Instruction::Return,
            ],
        }
    }
    pub fn of_module(db: &Database, module: Module) -> Option<Self> {
        let lir = db.lir(module.clone())?;
        Some(Self::of_module_lir(module, (*lir).clone()))
    }
}

impl Data {
    fn hash(&self, heap: &Heap) -> u64 {
        let mut state = DefaultHasher::new();
        self.hash_with_state(heap, &mut state);
        state.finish()
    }

    fn hash_with_state<H: Hasher>(&self, heap: &Heap, state: &mut H) {
        match self {
            Data::Int(int) => int.value.hash(state),
            Data::Text(text) => text.value.hash(state),
            Data::Symbol(symbol) => symbol.value.hash(state),
            Data::Struct(struct_) => {
                let mut s = 0;
                for (key, value) in struct_.iter() {
                    s ^= key.hash(heap);
                    s ^= value.hash(heap);
                }
                s.hash(state)
            }
            Data::Closure(closure) => {
                for captured in &closure.captured {
                    captured.hash_with_state(heap, state);
                }
                closure.num_args.hash(state);
                closure.body.hash(state);
            }
            Data::Builtin(builtin) => builtin.function.hash(state),
        }
    }

    pub fn equals(&self, heap: &Heap, other: &Self) -> bool {
        match (self, other) {
            (Data::Int(a), Data::Int(b)) => a.value == b.value,
            (Data::Text(a), Data::Text(b)) => a.value == b.value,
            (Data::Symbol(a), Data::Symbol(b)) => a.value == b.value,
            (Data::Struct(a), Data::Struct(b)) => a.equals(heap, b),
            (Data::Closure(_), Data::Closure(_)) => false,
            (Data::Builtin(a), Data::Builtin(b)) => a.function == b.function,
            _ => false,
        }
    }

    pub fn format(&self, heap: &Heap) -> String {
        match self {
            Data::Int(int) => format!("{}", int.value),
            Data::Text(text) => format!("\"{}\"", text.value),
            Data::Symbol(symbol) => symbol.value.to_string(),
            Data::Struct(struct_) => format!(
                "[{}]",
                struct_
                    .iter()
                    .map(|(key, value)| (key.format(heap), value.format(heap)))
                    .sorted_by(|(key_a, _), (key_b, _)| key_a.cmp(key_b))
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Data::Closure(_) => "{…}".to_string(),
            Data::Builtin(builtin) => format!("builtin{:?}", builtin.function),
        }
    }

    pub fn children(&self) -> Vec<Pointer> {
        match self {
            Data::Int(_) | Data::Text(_) | Data::Symbol(_) | Data::Builtin(_) => vec![],
            Data::Struct(struct_) => struct_
                .iter()
                .flat_map(|(a, b)| vec![a, b].into_iter())
                .collect_vec(),
            Data::Closure(closure) => closure.captured.clone(),
        }
    }
}

impl Deref for Object {
    type Target = Data;

    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl Pointer {
    fn hash(&self, heap: &Heap) -> u64 {
        heap.get(*self).hash(heap)
    }
    fn hash_with_state<H: Hasher>(&self, heap: &Heap, state: &mut H) {
        heap.get(*self).hash_with_state(heap, state)
    }
    pub fn equals(&self, heap: &Heap, other: Self) -> bool {
        if *self == other {
            return true;
        }
        heap.get(*self).equals(heap, heap.get(other))
    }
    pub fn format(&self, heap: &Heap) -> String {
        heap.get(*self).format(heap)
    }
}
<|endoftext|>


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

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length();
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line >= min(0, self.lines.len() - adjust as uint) {
            self.edit_point.index = self.current_line_length();
            self.edit_point.line = self.lines.len() - 1;
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            if self.multiline {
                let remaining = self.edit_point.index;
                if adjust.abs() as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(-1);
                    self.edit_point.index = self.current_line_length();
                    self.adjust_horizontal(adjust + remaining as int);
                } else {
                    self.edit_point.index = (self.edit_point.index as int + adjust) as uint;
                }
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            if self.multiline {
                let remaining = self.current_line_length() - self.edit_point.index;
                if adjust as uint > remaining {
                    self.edit_point.index = 0;
                    self.adjust_vertical(1);
                    self.adjust_horizontal(adjust - remaining as int);
                } else {
                    self.edit_point.index += adjust as uint;
                }
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<commit_msg>auto merge of #4267 : ema-fox/servo/textinput, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Common handling of keyboard input and state management for text input controls

use dom::bindings::codegen::Bindings::KeyboardEventBinding::KeyboardEventMethods;
use dom::bindings::js::JSRef;
use dom::keyboardevent::KeyboardEvent;
use servo_util::str::DOMString;

use std::cmp::{min, max};
use std::default::Default;

#[jstraceable]
struct TextPoint {
    /// 0-based line number
    line: uint,
    /// 0-based column number
    index: uint,
}

/// Encapsulated state for handling keyboard input in a single or multiline text input control.
#[jstraceable]
pub struct TextInput {
    /// Current text input content, split across lines without trailing '\n'
    lines: Vec<DOMString>,
    /// Current cursor input point
    edit_point: TextPoint,
    /// Selection range, beginning and end point that can span multiple lines.
    _selection: Option<(TextPoint, TextPoint)>,
    /// Is this a multiline input?
    multiline: bool,
}

/// Resulting action to be taken by the owner of a text input that is handling an event.
pub enum KeyReaction {
    TriggerDefaultAction,
    DispatchInput,
    Nothing,
}

impl Default for TextPoint {
    fn default() -> TextPoint {
        TextPoint {
            line: 0,
            index: 0,
        }
    }
}

/// Control whether this control should allow multiple lines.
#[deriving(PartialEq)]
pub enum Lines {
    Single,
    Multiple,
}

/// The direction in which to delete a character.
#[deriving(PartialEq)]
enum DeleteDir {
    Forward,
    Backward
}

impl TextInput {
    /// Instantiate a new text input control
    pub fn new(lines: Lines, initial: DOMString) -> TextInput {
        let mut i = TextInput {
            lines: vec!(),
            edit_point: Default::default(),
            _selection: None,
            multiline: lines == Multiple,
        };
        i.set_content(initial);
        i
    }

    /// Return the current line under the editing point
    fn get_current_line(&self) -> &DOMString {
        &self.lines[self.edit_point.line]
    }

    /// Insert a character at the current editing point
    fn insert_char(&mut self, ch: char) {
        //TODO: handle replacing selection with character
        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index);
            let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push(ch);
            new_line.push_str(suffix.as_slice());
            new_line
        };

        self.lines[self.edit_point.line] = new_line;
        self.edit_point.index += 1;
    }

    /// Remove a character at the current editing point
    fn delete_char(&mut self, dir: DeleteDir) {
        let forward = dir == Forward;

        //TODO: handle deleting selection
        let prefix_end = if forward {
            self.edit_point.index
        } else {
            if self.multiline {
                //TODO: handle backspacing from position 0 of current line
                if self.edit_point.index == 0 {
                    return;
                }
            } else if self.edit_point.index == 0 {
                return;
            }
            self.edit_point.index - 1
        };
        let suffix_start = if forward {
            let is_eol = self.edit_point.index == self.current_line_length();
            if self.multiline {
                //TODO: handle deleting from end position of current line
                if is_eol {
                    return;
                }
            } else if is_eol {
                return;
            }
            self.edit_point.index + 1
        } else {
            self.edit_point.index
        };

        let new_line = {
            let prefix = self.get_current_line().as_slice().slice_chars(0, prefix_end);
            let suffix = self.get_current_line().as_slice().slice_chars(suffix_start,
                                                                        self.current_line_length());
            let mut new_line = prefix.to_string();
            new_line.push_str(suffix);
            new_line
        };

        self.lines[self.edit_point.line] = new_line;

        if !forward {
            self.adjust_horizontal(-1);
        }
    }

    /// Return the length of the current line under the editing point.
    fn current_line_length(&self) -> uint {
        self.lines[self.edit_point.line].char_len()
    }

    /// Adjust the editing point position by a given of lines. The resulting column is
    /// as close to the original column position as possible.
    fn adjust_vertical(&mut self, adjust: int) {
        if !self.multiline {
            return;
        }

        if adjust < 0 && self.edit_point.line as int + adjust < 0 {
            self.edit_point.index = 0;
            self.edit_point.line = 0;
            return;
        } else if adjust > 0 && self.edit_point.line + adjust as uint >= self.lines.len() {
            self.edit_point.line = self.lines.len() - 1;
            self.edit_point.index = self.current_line_length();
            return;
        }

        self.edit_point.line = (self.edit_point.line as int + adjust) as uint;
        self.edit_point.index = min(self.current_line_length(), self.edit_point.index);
    }

    /// Adjust the editing point position by a given number of columns. If the adjustment
    /// requested is larger than is available in the current line, the editing point is
    /// adjusted vertically and the process repeats with the remaining adjustment requested.
    fn adjust_horizontal(&mut self, adjust: int) {
        if adjust < 0 {
            let remaining = self.edit_point.index;
            if adjust.abs() as uint > remaining && self.edit_point.line > 0 {
                self.adjust_vertical(-1);
                self.edit_point.index = self.current_line_length();
                self.adjust_horizontal(adjust + remaining as int);
            } else {
                self.edit_point.index = max(0, self.edit_point.index as int + adjust) as uint;
            }
        } else {
            let remaining = self.current_line_length() - self.edit_point.index;
            if adjust as uint > remaining && self.edit_point.line < self.lines.len() - 1 {
                self.edit_point.index = 0;
                self.adjust_vertical(1);
                self.adjust_horizontal(adjust - remaining as int);
            } else {
                self.edit_point.index = min(self.current_line_length(),
                                            self.edit_point.index + adjust as uint);
            }
        }
    }

    /// Deal with a newline input.
    fn handle_return(&mut self) -> KeyReaction {
        if !self.multiline {
            return TriggerDefaultAction;
        }

        //TODO: support replacing selection with newline
        let prefix = self.get_current_line().as_slice().slice_chars(0, self.edit_point.index).to_string();
        let suffix = self.get_current_line().as_slice().slice_chars(self.edit_point.index,
                                                                    self.current_line_length()).to_string();
        self.lines[self.edit_point.line] = prefix;
        self.lines.insert(self.edit_point.line + 1, suffix);
        return DispatchInput;
    }

    /// Process a given `KeyboardEvent` and return an action for the caller to execute.
    pub fn handle_keydown(&mut self, event: JSRef<KeyboardEvent>) -> KeyReaction {
        match event.Key().as_slice() {
            // printable characters have single-character key values
            c if c.len() == 1 => {
                self.insert_char(c.char_at(0));
                return DispatchInput;
            }
            "Space" => {
                self.insert_char(' ');
                DispatchInput
            }
            "Delete" => {
                self.delete_char(Forward);
                DispatchInput
            }
            "Backspace" => {
                self.delete_char(Backward);
                DispatchInput
            }
            "ArrowLeft" => {
                self.adjust_horizontal(-1);
                Nothing
            }
            "ArrowRight" => {
                self.adjust_horizontal(1);
                Nothing
            }
            "ArrowUp" => {
                self.adjust_vertical(-1);
                Nothing
            }
            "ArrowDown" => {
                self.adjust_vertical(1);
                Nothing
            }
            "Enter" => self.handle_return(),
            "Home" => {
                self.edit_point.index = 0;
                Nothing
            }
            "End" => {
                self.edit_point.index = self.current_line_length();
                Nothing
            }
            "PageUp" => {
                self.adjust_vertical(-28);
                Nothing
            }
            "PageDown" => {
                self.adjust_vertical(28);
                Nothing
            }
            "Tab" => TriggerDefaultAction,
            _ => Nothing,
        }
    }

    /// Get the current contents of the text input. Multiple lines are joined by \n.
    pub fn get_content(&self) -> DOMString {
        let mut content = "".to_string();
        for (i, line) in self.lines.iter().enumerate() {
            content.push_str(line.as_slice());
            if i < self.lines.len() - 1 {
                content.push('\n');
            }
        }
        content
    }

    /// Set the current contents of the text input. If this is control supports multiple lines,
    /// any \n encountered will be stripped and force a new logical line.
    pub fn set_content(&mut self, content: DOMString) {
        self.lines = if self.multiline {
            content.as_slice().split('\n').map(|s| s.to_string()).collect()
        } else {
            vec!(content)
        };
        self.edit_point.line = min(self.edit_point.line, self.lines.len() - 1);
        self.edit_point.index = min(self.edit_point.index, self.current_line_length() - 1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The binomial distribution.

use Rng;
use distributions::Distribution;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    /// Number of trials.
    n: u64,
    /// Probability of success.
    p: f64,
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters `n` (number
    /// of trials) and `p` (probability of success).
    ///
    /// Panics if `p < 0` or `p > 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p >= 0.0, "Binomial::new called with p < 0");
        assert!(p <= 1.0, "Binomial::new called with p > 1");
        Binomial { n, p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // Handle these values directly.
        if self.p == 0.0 {
            return 0;
        } else if self.p == 1.0 {
            return self.n;
        }

        // The binomial distribution is symmetrical with respect to p -> 1-p,
        // k -> n-k switch p so that it is less than 0.5 - this allows for lower
        // expected values we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        let result;

        // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
        // transformation of the binomial distribution is efficient. Otherwise,
        // the BTPE algorithm is used.
        //
        // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
        // random variate generation. Commun. ACM 31, 2 (February 1988),
        // 216-222. http://dx.doi.org/10.1145/42372.42381

        // Threshold for prefering the BINV algorithm. The paper suggests 10,
        // Ranlib uses 30, and GSL uses 14.
        const BINV_THRESHOLD: f64 = 10.;

        if (self.n as f64) * p < BINV_THRESHOLD &&
           self.n <= (::std::i32::MAX as u64) {
            // Use the BINV algorithm.
            let q = 1. - p;
            let s = p / q;
            let a = ((self.n + 1) as f64) * s;
            let mut r = q.powi(self.n as i32);
            let mut u: f64 = rng.gen();
            let mut x = 0;
            while u > r as f64 {
                u -= r;
                x += 1;
                r *= a / (x as f64) - s;
            }
            result = x;
        } else {
            // Use the BTPE algorithm.

            // Threshold for using the squeeze algorithm. This can be freely
            // chosen based on performance. Ranlib and GSL use 20.
            const SQUEEZE_THRESHOLD: i64 = 20;

            // Step 0: Calculate constants as functions of `n` and `p`.
            let n = self.n as f64;
            let r = p;
            let q = 1. - r;
            let f_m = n*r + r;
            let m = f_m as i64;
            // radius of triangle region, since height=1 also area of region
            let p1 = (2.195 * (n*r*q).sqrt() - 4.6 * q).floor() + 0.5;
            // tip of triangle
            let x_m = (m as f64) + 0.5;
            // left edge of triangle
            let x_l = x_m - p1;
            // right edge of triangle
            let x_r = x_m + p1;
            let c = 0.134 + 20.5 / (15.3 + (m as f64));
            // p1 + area of parallelogram region
            let p2 = p1 * (1. + 2. * c);

            fn lambda(a: f64) -> f64 {
                a * (1. + 0.5 * a)
            }

            let lambda_l = lambda((f_m - x_l) / (f_m - x_l * r));
            let lambda_r = lambda((x_r - f_m) / (x_r * q));
            // p1 + area of left tail
            let p3 = p2 + c / lambda_l;
            // p1 + area of right tail
            let p4 = p3 + c / lambda_r;

            // return value
            let mut y: i64;

            'outer: loop {
                // Step 1: Generate `u` for selecting the region. If region 1 is
                // selected, generate a triangularly distributed variate.
                let u = rng.gen_range(0., p4);
                let mut v = rng.gen_range(0., 1.);
                if !(u > p1) {
                    y = (x_m - p1 * v + u) as i64;
                    break;
                }

                loop {
                    // Step 2: Region 2, parallelograms. Check if region 2 is used. If
                    // so, generate `y`.
                    if !(u > p2) {
                        let x = x_l + (u - p1) / c;
                        v = v * c + 1.0 - (x - x_m).abs() / p1;
                        if v > 1. {
                            continue 'outer;
                        } else {
                            y = x as i64;
                            break;
                        }
                    }

                    // Step 3: Region 3, left exponential tail.
                    if !(u > p3) {
                        y = (x_l + v.ln() / lambda_l) as i64;
                        if y < 0 {
                            continue 'outer;
                        } else {
                            v *= (u - p2) * lambda_l;
                            break;
                        }
                    }

                    // Step 4: Region 4, right exponential tail.
                    y = (x_r - v.ln() / lambda_r) as i64;
                    if y > 0 && (y as u64) > self.n {
                        continue 'outer;
                    } else {
                        v *= (u - p3) * lambda_r;
                    }

                    break;
                }

                // Step 5: Acceptance/rejection comparison.

                // Step 5.0: Test for appropriate method of evaluating f(y).
                let k = (y - m).abs();
                if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * n*r*q - 1.) {
                    // Step 5.1: Evaluate f(y) via the recursive relationship. Start the
                    // search from the mode.
                    let s = r / q;
                    let a = s * (n + 1.);
                    let mut f = 1.0;
                    if m < y {
                        let mut i = m;
                        loop {
                            i += 1;
                            f *= a / (i as f64) - s;
                            if i == y {
                                break;
                            }
                        }
                    } else if m > y {
                        let mut i = y;
                        loop {
                            i += 1;
                            f /= a / (i as f64) - s;
                            if i == m {
                                break;
                            }
                        }
                    }
                    if v > f {
                        continue;
                    } else {
                        break;
                    }
                }

                // Step 5.2: Squeezing. Check the value of ln(v) againts upper and
                // lower bound of ln(f(y)).
                let k = k as f64;
                let rho = (k / (n*r*q)) * ((k * (k / 3. + 0.625) + 1./6.) / (n*r*q) + 0.5);
                let t = -0.5 * k*k / (n*r*q);
                let alpha = v.ln();
                if alpha < t - rho {
                    break;
                }
                if alpha > t + rho {
                    continue;
                }

                // Step 5.3: Final acceptance/rejection test.
                let x1 = (y + 1) as f64;
                let f1 = (m + 1) as f64;
                let z = ((n as i64) + 1 - m) as f64;
                let w = ((n as i64) - y + 1) as f64;

                fn stirling(a: f64) -> f64 {
                    let a2 = a * a;
                    (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
                }

                if alpha > x_m * (f1 / x1).ln()
                    + (n - (m as f64) + 0.5) * (z / w).ln()
                    + ((y - m) as f64) * (w * r / (x1 * q)).ln()
                    + stirling(f1) + stirling(z) + stirling(x1) + stirling(w)
                {
                    continue;
                }

                break;
            }
            assert!(y >= 0);
            result = y as u64;
        }

        // Invert the result for p < 0.5.
        if p != self.p {
            self.n - result
        } else {
            result
        }
    }
}

#[cfg(test)]
mod test {
    use Rng;
    use distributions::Distribution;
    use super::Binomial;

    fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
        let binomial = Binomial::new(n, p);

        let expected_mean = n as f64 * p;
        let expected_variance = n as f64 * p * (1.0 - p);

        let mut results = [0.0; 1000];
        for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }

        let mean = results.iter().sum::<f64>() / results.len() as f64;
        assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0,
                "mean: {}, expected_mean: {}", mean, expected_mean);

        let variance =
            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
            / results.len() as f64;
        assert!((variance - expected_variance).abs() < expected_variance / 10.0,
                "variance: {}, expected_variance: {}", variance, expected_variance);
    }

    #[test]
    fn test_binomial() {
        let mut rng = ::test::rng(351);
        test_binomial_mean_and_variance(150, 0.1, &mut rng);
        test_binomial_mean_and_variance(70, 0.6, &mut rng);
        test_binomial_mean_and_variance(40, 0.5, &mut rng);
        test_binomial_mean_and_variance(20, 0.7, &mut rng);
        test_binomial_mean_and_variance(20, 0.5, &mut rng);
    }

    #[test]
    fn test_binomial_end_points() {
        let mut rng = ::test::rng(352);
        assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
        assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<commit_msg>Binomial: Simplify code<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2016-2017 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The binomial distribution.

use Rng;
use distributions::Distribution;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    /// Number of trials.
    n: u64,
    /// Probability of success.
    p: f64,
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters `n` (number
    /// of trials) and `p` (probability of success).
    ///
    /// Panics if `p < 0` or `p > 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p >= 0.0, "Binomial::new called with p < 0");
        assert!(p <= 1.0, "Binomial::new called with p > 1");
        Binomial { n, p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // Handle these values directly.
        if self.p == 0.0 {
            return 0;
        } else if self.p == 1.0 {
            return self.n;
        }

        // The binomial distribution is symmetrical with respect to p -> 1-p,
        // k -> n-k switch p so that it is less than 0.5 - this allows for lower
        // expected values we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        let result;
        let q = 1. - p;

        // For small n * min(p, 1 - p), the BINV algorithm based on the inverse
        // transformation of the binomial distribution is efficient. Otherwise,
        // the BTPE algorithm is used.
        //
        // Voratas Kachitvichyanukul and Bruce W. Schmeiser. 1988. Binomial
        // random variate generation. Commun. ACM 31, 2 (February 1988),
        // 216-222. http://dx.doi.org/10.1145/42372.42381

        // Threshold for prefering the BINV algorithm. The paper suggests 10,
        // Ranlib uses 30, and GSL uses 14.
        const BINV_THRESHOLD: f64 = 10.;

        if (self.n as f64) * p < BINV_THRESHOLD &&
           self.n <= (::std::i32::MAX as u64) {
            // Use the BINV algorithm.
            let s = p / q;
            let a = ((self.n + 1) as f64) * s;
            let mut r = q.powi(self.n as i32);
            let mut u: f64 = rng.gen();
            let mut x = 0;
            while u > r as f64 {
                u -= r;
                x += 1;
                r *= a / (x as f64) - s;
            }
            result = x;
        } else {
            // Use the BTPE algorithm.

            // Threshold for using the squeeze algorithm. This can be freely
            // chosen based on performance. Ranlib and GSL use 20.
            const SQUEEZE_THRESHOLD: i64 = 20;

            // Step 0: Calculate constants as functions of `n` and `p`.
            let n = self.n as f64;
            let f_m = n*p + p;
            let m = f_m as i64;
            // radius of triangle region, since height=1 also area of region
            let p1 = (2.195 * (n*p*q).sqrt() - 4.6 * q).floor() + 0.5;
            // tip of triangle
            let x_m = (m as f64) + 0.5;
            // left edge of triangle
            let x_l = x_m - p1;
            // right edge of triangle
            let x_r = x_m + p1;
            let c = 0.134 + 20.5 / (15.3 + (m as f64));
            // p1 + area of parallelogram region
            let p2 = p1 * (1. + 2. * c);

            fn lambda(a: f64) -> f64 {
                a * (1. + 0.5 * a)
            }

            let lambda_l = lambda((f_m - x_l) / (f_m - x_l * p));
            let lambda_r = lambda((x_r - f_m) / (x_r * q));
            // p1 + area of left tail
            let p3 = p2 + c / lambda_l;
            // p1 + area of right tail
            let p4 = p3 + c / lambda_r;

            // return value
            let mut y: i64;

            loop {
                // Step 1: Generate `u` for selecting the region. If region 1 is
                // selected, generate a triangularly distributed variate.
                let u = rng.gen_range(0., p4);
                let mut v = rng.gen_range(0., 1.);
                if !(u > p1) {
                    y = (x_m - p1 * v + u) as i64;
                    break;
                }

                if !(u > p2) {
                    // Step 2: Region 2, parallelograms. Check if region 2 is
                    // used. If so, generate `y`.
                    let x = x_l + (u - p1) / c;
                    v = v * c + 1.0 - (x - x_m).abs() / p1;
                    if v > 1. {
                        continue;
                    } else {
                        y = x as i64;
                    }
                } else if !(u > p3) {
                    // Step 3: Region 3, left exponential tail.
                    y = (x_l + v.ln() / lambda_l) as i64;
                    if y < 0 {
                        continue;
                    } else {
                        v *= (u - p2) * lambda_l;
                    }
                } else {
                    // Step 4: Region 4, right exponential tail.
                    y = (x_r - v.ln() / lambda_r) as i64;
                    if y > 0 && (y as u64) > self.n {
                        continue;
                    } else {
                        v *= (u - p3) * lambda_r;
                    }
                }

                // Step 5: Acceptance/rejection comparison.

                // Step 5.0: Test for appropriate method of evaluating f(y).
                let k = (y - m).abs();
                if !(k > SQUEEZE_THRESHOLD && (k as f64) < 0.5 * n*p*q - 1.) {
                    // Step 5.1: Evaluate f(y) via the recursive relationship. Start the
                    // search from the mode.
                    let s = p / q;
                    let a = s * (n + 1.);
                    let mut f = 1.0;
                    if m < y {
                        let mut i = m;
                        loop {
                            i += 1;
                            f *= a / (i as f64) - s;
                            if i == y {
                                break;
                            }
                        }
                    } else if m > y {
                        let mut i = y;
                        loop {
                            i += 1;
                            f /= a / (i as f64) - s;
                            if i == m {
                                break;
                            }
                        }
                    }
                    if v > f {
                        continue;
                    } else {
                        break;
                    }
                }

                // Step 5.2: Squeezing. Check the value of ln(v) againts upper and
                // lower bound of ln(f(y)).
                let k = k as f64;
                let rho = (k / (n*p*q)) * ((k * (k / 3. + 0.625) + 1./6.) / (n*p*q) + 0.5);
                let t = -0.5 * k*k / (n*p*q);
                let alpha = v.ln();
                if alpha < t - rho {
                    break;
                }
                if alpha > t + rho {
                    continue;
                }

                // Step 5.3: Final acceptance/rejection test.
                let x1 = (y + 1) as f64;
                let f1 = (m + 1) as f64;
                let z = ((n as i64) + 1 - m) as f64;
                let w = ((n as i64) - y + 1) as f64;

                fn stirling(a: f64) -> f64 {
                    let a2 = a * a;
                    (13860. - (462. - (132. - (99. - 140. / a2) / a2) / a2) / a2) / a / 166320.
                }

                if alpha > x_m * (f1 / x1).ln()
                    + (n - (m as f64) + 0.5) * (z / w).ln()
                    + ((y - m) as f64) * (w * p / (x1 * q)).ln()
                    + stirling(f1) + stirling(z) + stirling(x1) + stirling(w)
                {
                    continue;
                }

                break;
            }
            assert!(y >= 0);
            result = y as u64;
        }

        // Invert the result for p < 0.5.
        if p != self.p {
            self.n - result
        } else {
            result
        }
    }
}

#[cfg(test)]
mod test {
    use Rng;
    use distributions::Distribution;
    use super::Binomial;

    fn test_binomial_mean_and_variance<R: Rng>(n: u64, p: f64, rng: &mut R) {
        let binomial = Binomial::new(n, p);

        let expected_mean = n as f64 * p;
        let expected_variance = n as f64 * p * (1.0 - p);

        let mut results = [0.0; 1000];
        for i in results.iter_mut() { *i = binomial.sample(rng) as f64; }

        let mean = results.iter().sum::<f64>() / results.len() as f64;
        assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0,
                "mean: {}, expected_mean: {}", mean, expected_mean);

        let variance =
            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
            / results.len() as f64;
        assert!((variance - expected_variance).abs() < expected_variance / 10.0,
                "variance: {}, expected_variance: {}", variance, expected_variance);
    }

    #[test]
    fn test_binomial() {
        let mut rng = ::test::rng(351);
        test_binomial_mean_and_variance(150, 0.1, &mut rng);
        test_binomial_mean_and_variance(70, 0.6, &mut rng);
        test_binomial_mean_and_variance(40, 0.5, &mut rng);
        test_binomial_mean_and_variance(20, 0.7, &mut rng);
        test_binomial_mean_and_variance(20, 0.5, &mut rng);
    }

    #[test]
    fn test_binomial_end_points() {
        let mut rng = ::test::rng(352);
        assert_eq!(rng.sample(Binomial::new(20, 0.0)), 0);
        assert_eq!(rng.sample(Binomial::new(20, 1.0)), 20);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<|endoftext|>


<commit_before>use anyhow::Context as _;
use cpal::{
    traits::{DeviceTrait as _, HostTrait as _, StreamTrait as _},
    Stream,
};
use crossbeam::queue::SegQueue;
use gba::{Command, GbaAudioSampler};
use pyrite::GbaHandle;
use std::sync::Arc;

const COMMANDS_CHUNK_SIZE: usize = 64;

pub fn run(gba: GbaHandle) -> anyhow::Result<Stream> {
    let host = cpal::default_host();
    let device = host
        .default_output_device()
        .ok_or_else(|| anyhow::Error::msg("no default output device"))?;
    let config = device
        .default_output_config()
        .context("error retrieving default output configuration")?;
    let commands_buffer_queue: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>> =
        Arc::new(SegQueue::new());

    let mut sound_source =
        GbaSoundSource::new(config.sample_rate().0, Arc::clone(&commands_buffer_queue));
    let channels = config.channels() as usize;
    let stream = device
        .build_output_stream(
            &config.into(),
            move |data: &mut [f32], _| sound_source.output(channels, data),
            |err| {
                log::error!("audio stream error: {err}");
            },
        )
        .context("failed to build output stream")?;
    stream.play().context("failed to play audio stream")?;

    let mut last_chunk_count = 0usize;
    gba.on_frame(move |gba, _| {
        let gba_audio_commands = gba.audio().commands();

        // Check to make sure that we have at most 2 frames worth of commands
        // waiting to be processed. If there are already two, then we just miss this
        // frame of audio commands.
        if commands_buffer_queue.len() <= last_chunk_count {
            last_chunk_count = 0;
            gba_audio_commands
                .chunks(COMMANDS_CHUNK_SIZE)
                .for_each(|src_chunk| {
                    let mut chunk = [Command::Wait(0); COMMANDS_CHUNK_SIZE];
                    (&mut chunk[..src_chunk.len()]).copy_from_slice(src_chunk);
                    commands_buffer_queue.push(chunk);
                    last_chunk_count += 1;
                });
        } else {
            log::debug!("missed frame audio command queue");
        }
    });
    Ok(stream)
}

struct GbaSoundSource {
    sampler: GbaAudioSampler,
    commands: Box<[Command; COMMANDS_CHUNK_SIZE]>,
    commands_idx: usize,
    commands_buffer: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>>,
}

impl GbaSoundSource {
    fn new(frequency: u32, commands_buffer: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>>) -> Self {
        GbaSoundSource {
            sampler: GbaAudioSampler::new(frequency),
            commands: Box::new([Command::Wait(0); COMMANDS_CHUNK_SIZE]),
            commands_idx: 0,
            commands_buffer,
        }
    }

    fn try_refill_buffer(&mut self) {
        if let Some(chunk) = self.commands_buffer.pop() {
            *self.commands = chunk;
            self.commands_idx = 0;
        }
    }

    fn next_command(&mut self) -> Option<Command> {
        if self.commands_idx >= COMMANDS_CHUNK_SIZE {
            self.try_refill_buffer();
        }

        if self.commands_idx >= COMMANDS_CHUNK_SIZE {
            None
        } else {
            let idx = self.commands_idx;
            self.commands_idx += 1;
            Some(self.commands[idx])
        }
    }

    fn output(&mut self, channels: usize, samples: &mut [f32]) {
        samples.chunks_exact_mut(channels).for_each(|frame| {
            while self.sampler.needs_commands() {
                if let Some(command) = self.next_command() {
                    self.sampler.command(command);
                } else {
                    break;
                }
            }

            if channels >= 2 {
                (frame[0], frame[1]) = self.sampler.frame(0.15);
            } else {
                let (left, right) = self.sampler.frame(0.15);
                frame[0] = (left + right) / 2.0;
            }

            if channels > 2 {
                frame[2..].fill(0.0);
            }
        });
    }
}
<commit_msg>Print some debug information when audio is initialized.<commit_after>use anyhow::Context as _;
use cpal::{
    traits::{DeviceTrait as _, HostTrait as _, StreamTrait as _},
    Stream,
};
use crossbeam::queue::SegQueue;
use gba::{Command, GbaAudioSampler};
use pyrite::GbaHandle;
use std::sync::Arc;

const COMMANDS_CHUNK_SIZE: usize = 64;

pub fn run(gba: GbaHandle) -> anyhow::Result<Stream> {
    let host = cpal::default_host();
    let device = host
        .default_output_device()
        .ok_or_else(|| anyhow::Error::msg("no default output device"))?;
    let config = device
        .default_output_config()
        .context("error retrieving default output configuration")?;
    let commands_buffer_queue: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>> =
        Arc::new(SegQueue::new());

    log::debug!("audio sample rate: {}", config.sample_rate().0);
    log::debug!("audio channels: {}", config.channels());
    log::debug!("audio sample format: {:?}", config.sample_format());
    log::debug!("audio buffer size: {:?}", config.buffer_size());

    let mut sound_source =
        GbaSoundSource::new(config.sample_rate().0, Arc::clone(&commands_buffer_queue));
    let channels = config.channels() as usize;
    let stream = device
        .build_output_stream(
            &config.into(),
            move |data: &mut [f32], _| sound_source.output(channels, data),
            |err| {
                log::error!("audio stream error: {err}");
            },
        )
        .context("failed to build output stream")?;
    stream.play().context("failed to play audio stream")?;

    let mut last_chunk_count = 0usize;
    gba.on_frame(move |gba, _| {
        let gba_audio_commands = gba.audio().commands();

        // Check to make sure that we have at most 2 frames worth of commands
        // waiting to be processed. If there are already two, then we just miss this
        // frame of audio commands.
        if commands_buffer_queue.len() <= last_chunk_count {
            last_chunk_count = 0;
            gba_audio_commands
                .chunks(COMMANDS_CHUNK_SIZE)
                .for_each(|src_chunk| {
                    let mut chunk = [Command::Wait(0); COMMANDS_CHUNK_SIZE];
                    (&mut chunk[..src_chunk.len()]).copy_from_slice(src_chunk);
                    commands_buffer_queue.push(chunk);
                    last_chunk_count += 1;
                });
        } else {
            log::debug!("missed frame audio command queue");
        }
    });
    Ok(stream)
}

struct GbaSoundSource {
    sampler: GbaAudioSampler,
    commands: Box<[Command; COMMANDS_CHUNK_SIZE]>,
    commands_idx: usize,
    commands_buffer: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>>,
}

impl GbaSoundSource {
    fn new(frequency: u32, commands_buffer: Arc<SegQueue<[Command; COMMANDS_CHUNK_SIZE]>>) -> Self {
        GbaSoundSource {
            sampler: GbaAudioSampler::new(frequency),
            commands: Box::new([Command::Wait(0); COMMANDS_CHUNK_SIZE]),
            commands_idx: 0,
            commands_buffer,
        }
    }

    fn try_refill_buffer(&mut self) {
        if let Some(chunk) = self.commands_buffer.pop() {
            *self.commands = chunk;
            self.commands_idx = 0;
        }
    }

    fn next_command(&mut self) -> Option<Command> {
        if self.commands_idx >= COMMANDS_CHUNK_SIZE {
            self.try_refill_buffer();
        }

        if self.commands_idx >= COMMANDS_CHUNK_SIZE {
            None
        } else {
            let idx = self.commands_idx;
            self.commands_idx += 1;
            Some(self.commands[idx])
        }
    }

    fn output(&mut self, channels: usize, samples: &mut [f32]) {
        samples.chunks_exact_mut(channels).for_each(|frame| {
            while self.sampler.needs_commands() {
                if let Some(command) = self.next_command() {
                    self.sampler.command(command);
                } else {
                    break;
                }
            }

            if channels >= 2 {
                (frame[0], frame[1]) = self.sampler.frame(0.15);
            } else {
                let (left, right) = self.sampler.frame(0.15);
                frame[0] = (left + right) / 2.0;
            }

            if channels > 2 {
                frame[2..].fill(0.0);
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate cbor;
extern crate rustc_serialize;
extern crate secstr;
extern crate rusterpassword;
extern crate libc;
extern crate libsodium_sys as sodium;
extern crate sodiumoxide;

use secstr::*;
use rusterpassword::*;
use cbor::{Encoder, Decoder};
use libc::size_t;
use std::collections::btree_map::{BTreeMap, Keys};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305 as secbox;

macro_rules! try_custom {
    ($e:expr, $err:expr) => (match $e { Ok(e) => e, Err(_) => return Err($err) })
}

macro_rules! try_custom_option {
    ($e:expr, $err:expr) => (match $e { Some(e) => e, None => return Err($err) })
}

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Vault {
    version: u16,
    padding: Vec<u8>,
    entries: BTreeMap<String, (Vec<u8>, u32, Vec<u8>)> // mapping: name → nonce, counter, encrypted Entry
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct Entry {
    fields: BTreeMap<String, Field>
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum Field {
    Derived { counter: u32, site_name: Option<String>, usage: DerivedUsage },
    Stored { data: SecStr, usage: StoredUsage }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum DerivedUsage {
    Password(PasswordTemplate)
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum StoredUsage {
    Password
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum PasswordTemplate {
    Maximum, Long, Medium, Short, Basic, Pin
}

#[derive(Debug)]
pub enum EntryError {
    WrongEntriesKeyLength,
    WrongNonceLength,
    SeedGenerationError,
    DecryptionError,
    EncodingError,
    DecodingError,
    EntryNotFound
}

impl Vault {
    pub fn entry_names(&self) -> Keys<String, (Vec<u8>, u32, Vec<u8>)> {
        self.entries.keys()
    }

    pub fn get_entry(&self, entries_key: &SecStr, name: &str) -> Result<Entry, EntryError> {
        if let Some(&(ref nonce, counter, ref ciphertext)) = self.entries.get(name) {
            let nonce_wrapped = try_custom_option!(secbox::Nonce::from_slice(&nonce), EntryError::WrongNonceLength);
            let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
            let plaintext = SecStr::new(try_custom!(secbox::open(&ciphertext, &nonce_wrapped, &entry_key_wrapped), EntryError::DecryptionError));
            Ok(try_custom!(try_custom_option!(Decoder::from_bytes(plaintext.unsecure()).decode::<Entry>().next(), EntryError::DecodingError), EntryError::DecodingError))
        } else {
            Err(EntryError::EntryNotFound)
        }
    }

    pub fn put_entry(&mut self, entries_key: &SecStr, name: &str, entry: &Entry) -> Result<(), EntryError> {
        let counter = match self.entries.get(name) {
            Some(&(_, counter, _)) => counter + 1,
            _ => 1
        };
        let nonce_wrapped = secbox::gen_nonce();
        let secbox::Nonce(nonce) = nonce_wrapped;
        let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
        let mut e = Encoder::from_memory();
        try_custom!(e.encode(&[entry]), EntryError::EncodingError);
        let plaintext = SecStr::new(e.into_bytes());
        let ciphertext = secbox::seal(plaintext.unsecure(), &nonce_wrapped, &entry_key_wrapped);
        self.entries.insert(String::from(name), (nonce.to_vec(), counter, ciphertext));
        Ok(())
    }

}

fn gen_entry_key(entries_key: &SecStr, name: &str, counter: u32) -> Result<secbox::Key, EntryError> {
    let entry_key = try_custom!(gen_site_seed(entries_key, name, counter), EntryError::SeedGenerationError);
    Ok(try_custom_option!(secbox::Key::from_slice(entry_key.unsecure()), EntryError::WrongEntriesKeyLength))
}

pub fn gen_entries_key(master_key: &SecStr) -> SecStr {
    let mut msg = vec![];
    msg.extend(b"technology.unrelenting.freepass");
    let mut dst = Vec::<u8>::with_capacity(64);
    unsafe {
        sodium::crypto_generichash_blake2b(
            dst.as_mut_ptr() as *mut u8, 64,
            msg.as_ptr(), msg.len() as size_t,
            master_key.unsecure().as_ptr() as *const u8,
            master_key.unsecure().len() as size_t);
        dst.set_len(64);
    }
    SecStr::new(dst)
}

#[cfg(test)]
mod tests {
    use super::*;
    use secstr::*;
    use rusterpassword::*;
    use std::collections::btree_map::BTreeMap;

    #[test]
    fn test_roundtrip() {
        let mut fs = BTreeMap::new();
        fs.insert(String::from("password"), Field::Derived { counter: 4, site_name: Some(String::from("twitter.com")), usage: DerivedUsage::Password(PasswordTemplate::Maximum) });
        fs.insert(String::from("old_password"), Field::Stored { data: SecStr::from("h0rse"), usage: StoredUsage::Password });
        let twitter = Entry { fields: fs };
        let mut vault = Vault { version: 0, padding: b"".to_vec(), entries: BTreeMap::new() };
        let master_key = gen_master_key(SecStr::from("Correct Horse Battery Staple"), "Clarke Griffin").unwrap();
        let entries_key = gen_entries_key(&master_key);
        vault.put_entry(&entries_key, "twitter", &twitter).unwrap();
        assert!(vault.get_entry(&entries_key, "twitter").unwrap() == twitter);
    }
}
<commit_msg>error handling things<commit_after>extern crate cbor;
extern crate rustc_serialize;
extern crate secstr;
extern crate rusterpassword;
extern crate libc;
extern crate libsodium_sys as sodium;
extern crate sodiumoxide;

use secstr::SecStr;
use rusterpassword::gen_site_seed;
use cbor::{Encoder, Decoder, CborError};
use libc::size_t;
use std::collections::btree_map::{BTreeMap, Keys};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305 as secbox;

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Vault {
    version: u16,
    padding: Vec<u8>,
    entries: BTreeMap<String, (Vec<u8>, u32, Vec<u8>)> // mapping: name → nonce, counter, encrypted Entry
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct Entry {
    fields: BTreeMap<String, Field>
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum Field {
    Derived { counter: u32, site_name: Option<String>, usage: DerivedUsage },
    Stored { data: SecStr, usage: StoredUsage }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum DerivedUsage {
    Password(PasswordTemplate)
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum StoredUsage {
    Password
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum PasswordTemplate {
    Maximum, Long, Medium, Short, Basic, Pin
}

#[derive(Debug)]
pub enum EntryError {
    WrongEntriesKeyLength,
    WrongNonceLength,
    SeedGenerationError,
    DecryptionError,
    CodecError(CborError),
    DataError,
    EntryNotFound
}

impl From<CborError> for EntryError {
    fn from(err: CborError) -> EntryError {
        EntryError::CodecError(err)
    }
}

pub type EntryResult<T> = Result<T, EntryError>;

impl Vault {

    pub fn entry_names(&self) -> Keys<String, (Vec<u8>, u32, Vec<u8>)> {
        self.entries.keys()
    }

    pub fn get_entry(&self, entries_key: &SecStr, name: &str) -> EntryResult<Entry> {
        if let Some(&(ref nonce, counter, ref ciphertext)) = self.entries.get(name) {
            let nonce_wrapped = try!(secbox::Nonce::from_slice(&nonce).ok_or(EntryError::WrongNonceLength));
            let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
            let plaintext = SecStr::new(try!(secbox::open(&ciphertext, &nonce_wrapped, &entry_key_wrapped).map_err(|_| EntryError::DecryptionError)));
            Ok(try!(try!(Decoder::from_bytes(plaintext.unsecure()).decode::<Entry>().next().ok_or(EntryError::DataError))))
        } else {
            Err(EntryError::EntryNotFound)
        }
    }

    pub fn put_entry(&mut self, entries_key: &SecStr, name: &str, entry: &Entry) -> EntryResult<()> {
        let counter = match self.entries.get(name) {
            Some(&(_, counter, _)) => counter + 1,
            _ => 1
        };
        let nonce_wrapped = secbox::gen_nonce();
        let secbox::Nonce(nonce) = nonce_wrapped;
        let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
        let mut e = Encoder::from_memory();
        try!(e.encode(&[entry]));
        let plaintext = SecStr::new(e.into_bytes());
        let ciphertext = secbox::seal(plaintext.unsecure(), &nonce_wrapped, &entry_key_wrapped);
        self.entries.insert(String::from(name), (nonce.to_vec(), counter, ciphertext));
        Ok(())
    }

}

fn gen_entry_key(entries_key: &SecStr, name: &str, counter: u32) -> EntryResult<secbox::Key> {
    let entry_key = try!(gen_site_seed(entries_key, name, counter).map_err(|_| EntryError::SeedGenerationError));
    Ok(try!(secbox::Key::from_slice(entry_key.unsecure()).ok_or(EntryError::WrongEntriesKeyLength)))
}

pub fn gen_entries_key(master_key: &SecStr) -> SecStr {
    let mut msg = vec![];
    msg.extend(b"technology.unrelenting.freepass");
    let mut dst = Vec::<u8>::with_capacity(64);
    unsafe {
        sodium::crypto_generichash_blake2b(
            dst.as_mut_ptr() as *mut u8, 64,
            msg.as_ptr(), msg.len() as u64,
            master_key.unsecure().as_ptr() as *const u8,
            master_key.unsecure().len() as size_t);
        dst.set_len(64);
    }
    SecStr::new(dst)
}

#[cfg(test)]
mod tests {
    use super::*;
    use secstr::*;
    use rusterpassword::*;
    use std::collections::btree_map::BTreeMap;

    #[test]
    fn test_roundtrip_entry() {
        let mut fs = BTreeMap::new();
        fs.insert(String::from("password"), Field::Derived { counter: 4, site_name: Some(String::from("twitter.com")), usage: DerivedUsage::Password(PasswordTemplate::Maximum) });
        fs.insert(String::from("old_password"), Field::Stored { data: SecStr::from("h0rse"), usage: StoredUsage::Password });
        let twitter = Entry { fields: fs };
        let mut vault = Vault { version: 0, padding: b"".to_vec(), entries: BTreeMap::new() };
        let master_key = gen_master_key(SecStr::from("Correct Horse Battery Staple"), "Clarke Griffin").unwrap();
        let entries_key = gen_entries_key(&master_key);
        vault.put_entry(&entries_key, "twitter", &twitter).unwrap();
        assert!(vault.get_entry(&entries_key, "twitter").unwrap() == twitter);
    }
}
<|endoftext|>


<commit_before>//! The rbattle game protocol.
//!
//! All hosts participating in an rbattle game have a complete copy of the
//! state, and the algorithm for evolving the state from one moment to the next
//! is strictly deterministic.
//!
//! Every effect the player can have on the game is represented as a
//! `state::Action` value. Given an initial state, and a record of which actions
//! were applied by which players on which turns, you can exactly recreate the
//! progression of the game. Since rbattle is such a simple game, there's only
//! one kind of action: toggling an outflow.
//!
//! In that light, the protocol focuses on gathering user actions, and
//! distributing them out in a way that helps apply them consistently. The
//! protocol has no means for communicating the game state. The only record of
//! the game state transmitted at all is a hash value to detect divergence,
//! which causes the game to end.
//!
//! For simplicity, we designate one host as the server; the protocol doesn't
//! provide for any resilience if the server goes down. All other hosts have TCP
//! connections to the server only.
//!
//! Game play is organized into 'turns', where turns are scheduled at fixed
//! intervals. (We'll aim for 33ms per turn, or 30 turns/second, and see how
//! that goes.) Clients send the server an action list every turn, even if it's
//! an empty action list; and the server broadcasts out the collected action
//! list for every turn, even if it's empty.
//!
//! The server is responsible for coordinating timing. For a given turn duration
//! T, the server broadcasts the list of gathered actions as soon as they are
//! available, but no sooner then T after the last broadcast.
//!
//! Clients should apply received action lists as soon as they are received,
//! advance their state, and send any collected actions immediately.

use map::MapParameters;
use jsonproto::JsonProto;
use scheduler::{CollectedActions, Notifier, PlayerActions, Scheduler};
use state::{Action, Player, SerializableState, State};

use futures::{Future};
use futures::future::ok;
use futures::sync::oneshot;
use tokio_proto::TcpServer;
use tokio_service::Service;

use std::io::{Error, ErrorKind};
use std::mem::replace;
use std::net::SocketAddr;
use std::sync::{Arc, mpsc, Mutex};
use std::thread;

#[derive(Clone)]
struct SchedulerService {
    scheduler: Arc<Mutex<Scheduler>>
}

/// Requests the server receives from clients.
#[derive(Debug, Serialize, Deserialize)]
enum Request {
    Join,
    Actions(PlayerActions),
}

/// The server's responses to those requests.
#[derive(Debug, Serialize, Deserialize)]
enum Response {
    Welcome { player: Player, state: SerializableState },
    GameFull,
    Turn(CollectedActions)
}

/// This impl allows `Scheduler` to resolve promises returned by
/// SchedulerService::call.
impl Notifier for oneshot::Sender<Response> {
    fn notify(self: Box<Self>, turn: CollectedActions) {
        self.send(Response::Turn(turn))
            .expect("oneshot notifier receiver died");
    }
}

/// This impl allows `Scheduler` to send the actions collected for a turn to the
/// local game.
impl Notifier for mpsc::Sender<CollectedActions> {
    fn notify(self: Box<Self>, turn: CollectedActions) {
        self.send(turn)
            .expect("mpsc notifier receiver died");
    }
}

impl Service for SchedulerService {
    type Request = Request;
    type Response = Response;
    type Error = Error;
    type Future = Box<Future<Item=Response, Error=Error>>;

    fn call(&self, req: Request) -> Self::Future {
        match req {
            Request::Join => {
                let mut guard = self.scheduler.lock().unwrap();
                match guard.player_join() {
                    Some((player, state)) =>
                        Box::new(ok(Response::Welcome { player, state })),
                    None =>
                        Box::new(ok(Response::GameFull))
                }
            },
            Request::Actions(actions) => {
                let (sender, receiver) = oneshot::channel();
                let mut guard = self.scheduler.lock().unwrap();
                guard.submit_actions(actions, Box::new(sender));

                // Turn oneshot errors into io::Error, as this service requires.
                let receiver = receiver.map_err(|e| Error::new(ErrorKind::Other, e));

                Box::new(receiver)
            }
        }
    }
}

/// A participant that has joined a game. This is the common trait that both client
/// and server sides implement.
pub trait Participant {
    /// Return a snapshot of the current state.
    fn snapshot(&self) -> State;

    /// Return the player number of this SynchronizedState.
    fn get_player(&self) -> Player;

    /// Submit `action` to be performed as soon as possible.
    fn request_action(&mut self, action: Action);
}

/// Information shared between the main thread and helper threads.
struct Shared {
    /// The player this state represents. Assigned by the server.
    player: Player,

    /// The current state of the game.
    state: State,

    /// The queue of actions to be sent to the scheduler on the next turn.
    pending: Vec<Action>
}

pub struct Server {
    /// The player on the local machine.
    player: Player,

    /// Information shared between the main thread, the server thread, and the
    /// scheduler thread.
    shared: Arc<Mutex<Shared>>,

    /// The scheduler we interact with to take turns.
    scheduler: Arc<Mutex<Scheduler>>
}

impl Server {
    pub fn new(addr: SocketAddr, params: MapParameters) -> Server {
        assert!(params.player_colors.len() >= 1);

        // Create a scheduler to coordinate turns amongst the players,
        // and add ourselves as the first player.
        let mut scheduler = Scheduler::new(State::new(params));
        let (player, current_state) = scheduler.player_join().unwrap();

        let scheduler = Arc::new(Mutex::new(scheduler));

        let shared = Arc::new(Mutex::new(Shared {
            player,
            state: State::from_serializable(current_state),
            pending: vec![]
        }));

        let (sender, receiver): (mpsc::Sender<CollectedActions>, _) = mpsc::channel();

        // Create a thread to apply actions received from the scheduler.
        // These variables get moved into the closure.
        let shared_handle = shared.clone();
        let scheduler_handle = scheduler.clone();
        let sender_handle = sender.clone();
        thread::spawn(move || {
            for collected_actions in receiver {
                let mut guard = shared_handle.lock().unwrap();
                assert_eq!(guard.state.turn + 1, collected_actions.turn);

                for action in collected_actions.actions {
                    guard.state.take_action(&action);
                }
                guard.state.advance();

                // We should have applied the same actions to the same state,
                // and gotten the same checksum.
                assert_eq!(guard.state.checksum(),
                           collected_actions.state_checksum);

                // Now that we've applied the actions from the prior turn,
                // submit whatever actions have been queued up in the mean time
                // as our next turn.
                let actions = PlayerActions {
                    player: guard.player,
                    turn: guard.state.turn,
                    actions: replace(&mut guard.pending, vec![])
                };

                // But drop the guard on the shared data first, to avoid
                // having to think about lock ordering.
                drop(guard);

                let mut guard = scheduler_handle.lock().unwrap();
                guard.submit_actions(actions, Box::new(sender_handle.clone()));
            }
        });

        // Spawn off a second thread to run the server.
        // This variable gets moved into the closure.
        let scheduler_handle = scheduler.clone();
        thread::spawn(move || {
            let server = TcpServer::new(JsonProto::<Request, Response>::new(), addr);
            server.serve(move || {
                Ok(SchedulerService { scheduler: scheduler_handle.clone() })
            });
        });

        // Get the ball rolling by submitting an empty first move.
        {
            let mut guard = scheduler.lock().unwrap();
            let actions = PlayerActions {
                player,
                turn: 0,
                actions: vec![]
            };
            guard.submit_actions(actions, Box::new(sender));
        }

        Server { player, shared, scheduler }
    }
}

impl Participant for Server {
    /// Return a snapshot of the current state.
    fn snapshot(&self) -> State {
        let guard = self.shared.lock().unwrap();
        guard.state.clone()
    }

    /// Return the player number of this SynchronizedState.
    fn get_player(&self) -> Player { self.player }

    /// Submit `action` to be performed as soon as possible.
    fn request_action(&mut self, action: Action) {
        let mut guard = self.shared.lock().unwrap();
        guard.pending.push(action);
    }
}
<commit_msg>Factor out process of applying CollectedActions to a Shared.<commit_after>//! The rbattle game protocol.
//!
//! All hosts participating in an rbattle game have a complete copy of the
//! state, and the algorithm for evolving the state from one moment to the next
//! is strictly deterministic.
//!
//! Every effect the player can have on the game is represented as a
//! `state::Action` value. Given an initial state, and a record of which actions
//! were applied by which players on which turns, you can exactly recreate the
//! progression of the game. Since rbattle is such a simple game, there's only
//! one kind of action: toggling an outflow.
//!
//! In that light, the protocol focuses on gathering user actions, and
//! distributing them out in a way that helps apply them consistently. The
//! protocol has no means for communicating the game state. The only record of
//! the game state transmitted at all is a hash value to detect divergence,
//! which causes the game to end.
//!
//! For simplicity, we designate one host as the server; the protocol doesn't
//! provide for any resilience if the server goes down. All other hosts have TCP
//! connections to the server only.
//!
//! Game play is organized into 'turns', where turns are scheduled at fixed
//! intervals. (We'll aim for 33ms per turn, or 30 turns/second, and see how
//! that goes.) Clients send the server an action list every turn, even if it's
//! an empty action list; and the server broadcasts out the collected action
//! list for every turn, even if it's empty.
//!
//! The server is responsible for coordinating timing. For a given turn duration
//! T, the server broadcasts the list of gathered actions as soon as they are
//! available, but no sooner then T after the last broadcast.
//!
//! Clients should apply received action lists as soon as they are received,
//! advance their state, and send any collected actions immediately.

use map::MapParameters;
use jsonproto::JsonProto;
use scheduler::{CollectedActions, Notifier, PlayerActions, Scheduler};
use state::{Action, Player, SerializableState, State};

use futures::{Future};
use futures::future::ok;
use futures::sync::oneshot;
use tokio_proto::TcpServer;
use tokio_service::Service;

use std::io::{Error, ErrorKind};
use std::mem::replace;
use std::net::SocketAddr;
use std::sync::{Arc, mpsc, Mutex};
use std::thread;

#[derive(Clone)]
struct SchedulerService {
    scheduler: Arc<Mutex<Scheduler>>
}

/// Requests the server receives from clients.
#[derive(Debug, Serialize, Deserialize)]
enum Request {
    Join,
    Actions(PlayerActions),
}

/// The server's responses to those requests.
#[derive(Debug, Serialize, Deserialize)]
enum Response {
    Welcome { player: Player, state: SerializableState },
    GameFull,
    Turn(CollectedActions)
}

/// This impl allows `Scheduler` to resolve promises returned by
/// SchedulerService::call.
impl Notifier for oneshot::Sender<Response> {
    fn notify(self: Box<Self>, turn: CollectedActions) {
        self.send(Response::Turn(turn))
            .expect("oneshot notifier receiver died");
    }
}

/// This impl allows `Scheduler` to send the actions collected for a turn to the
/// local game.
impl Notifier for mpsc::Sender<CollectedActions> {
    fn notify(self: Box<Self>, turn: CollectedActions) {
        self.send(turn)
            .expect("mpsc notifier receiver died");
    }
}

impl Service for SchedulerService {
    type Request = Request;
    type Response = Response;
    type Error = Error;
    type Future = Box<Future<Item=Response, Error=Error>>;

    fn call(&self, req: Request) -> Self::Future {
        match req {
            Request::Join => {
                let mut guard = self.scheduler.lock().unwrap();
                match guard.player_join() {
                    Some((player, state)) =>
                        Box::new(ok(Response::Welcome { player, state })),
                    None =>
                        Box::new(ok(Response::GameFull))
                }
            },
            Request::Actions(actions) => {
                let (sender, receiver) = oneshot::channel();
                let mut guard = self.scheduler.lock().unwrap();
                guard.submit_actions(actions, Box::new(sender));

                // Turn oneshot errors into io::Error, as this service requires.
                let receiver = receiver.map_err(|e| Error::new(ErrorKind::Other, e));

                Box::new(receiver)
            }
        }
    }
}

/// A participant that has joined a game. This is the common trait that both client
/// and server sides implement.
pub trait Participant {
    /// Return a snapshot of the current state.
    fn snapshot(&self) -> State;

    /// Return the player number of this SynchronizedState.
    fn get_player(&self) -> Player;

    /// Submit `action` to be performed as soon as possible.
    fn request_action(&mut self, action: Action);
}

/// Information shared between the main thread and helper threads.
struct Shared {
    /// The player this state represents. Assigned by the server.
    player: Player,

    /// The current state of the game.
    state: State,

    /// The queue of actions to be sent to the scheduler on the next turn.
    pending: Vec<Action>
}

impl Shared {
    fn apply_collected_actions(&mut self,
                               collected_actions: CollectedActions)
                               -> PlayerActions
    {
        assert_eq!(self.state.turn + 1, collected_actions.turn);

        for action in collected_actions.actions {
            self.state.take_action(&action);
        }
        self.state.advance();

        // We should have applied the same actions to the same state,
        // and gotten the same checksum.
        assert_eq!(self.state.checksum(),
                   collected_actions.state_checksum);

        // Now that we've applied the actions from the prior turn, return
        // whatever actions have been queued up in the mean time as our next
        // turn.
        PlayerActions {
            player: self.player,
            turn: self.state.turn,
            actions: replace(&mut self.pending, vec![])
        }
    }
}

pub struct Server {
    /// The player on the local machine.
    player: Player,

    /// Information shared between the main thread, the server thread, and the
    /// scheduler thread.
    shared: Arc<Mutex<Shared>>,

    /// The scheduler we interact with to take turns.
    scheduler: Arc<Mutex<Scheduler>>
}

impl Server {
    pub fn new(addr: SocketAddr, params: MapParameters) -> Server {
        assert!(params.player_colors.len() >= 1);

        // Create a scheduler to coordinate turns amongst the players,
        // and add ourselves as the first player.
        let mut scheduler = Scheduler::new(State::new(params));
        let (player, current_state) = scheduler.player_join().unwrap();

        let scheduler = Arc::new(Mutex::new(scheduler));

        let shared = Arc::new(Mutex::new(Shared {
            player,
            state: State::from_serializable(current_state),
            pending: vec![]
        }));

        let (sender, receiver): (mpsc::Sender<CollectedActions>, _) = mpsc::channel();

        // Create a thread to apply actions received from the scheduler.
        // These variables get moved into the closure.
        let shared_handle = shared.clone();
        let scheduler_handle = scheduler.clone();
        let sender_handle = sender.clone();
        thread::spawn(move || {
            for collected_actions in receiver {
                let mut guard = shared_handle.lock().unwrap();
                let next_actions = guard.apply_collected_actions(collected_actions);

                // Drop the guard on the shared data first, to avoid having to
                // think about lock ordering.
                drop(guard);

                let mut guard = scheduler_handle.lock().unwrap();
                guard.submit_actions(next_actions, Box::new(sender_handle.clone()));
            }
        });

        // Spawn off a second thread to run the server.
        // This variable gets moved into the closure.
        let scheduler_handle = scheduler.clone();
        thread::spawn(move || {
            let server = TcpServer::new(JsonProto::<Request, Response>::new(), addr);
            server.serve(move || {
                Ok(SchedulerService { scheduler: scheduler_handle.clone() })
            });
        });

        // Get the ball rolling by submitting an empty first move.
        {
            let mut guard = scheduler.lock().unwrap();
            let actions = PlayerActions {
                player,
                turn: 0,
                actions: vec![]
            };
            guard.submit_actions(actions, Box::new(sender));
        }

        Server { player, shared, scheduler }
    }
}

impl Participant for Server {
    /// Return a snapshot of the current state.
    fn snapshot(&self) -> State {
        let guard = self.shared.lock().unwrap();
        guard.state.clone()
    }

    /// Return the player number of this SynchronizedState.
    fn get_player(&self) -> Player { self.player }

    /// Submit `action` to be performed as soon as possible.
    fn request_action(&mut self, action: Action) {
        let mut guard = self.shared.lock().unwrap();
        guard.pending.push(action);
    }
}
<|endoftext|>