<commit_before>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher, Witness};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    /// A set of rules, stating what must be done in which circumstance.
    rules: Vec<Trigger>,

    /// Either `None` if the application is not launched, or `Some(tx)`,
    /// where `tx` is a channel used to communicate with the thread
    /// running the application.
    command_sender: Option<Sender<MonitorOp>>,
}

impl<'a> MonitorApp {
    /// Index-safe iteration through all the possible
    /// allocations/individual devices/inputs.
    fn iter_state_index(&self) -> Vec<InputBinding>
    {
        // FIXME: Several possible optimizations here, including
        // caching the vector.
        let mut vec = Vec::new();
        for (req, allocation, allocation_index) in Zip::new((&self.requirements, &self.allocations, 0..)) {
            for (individual_device, individual_device_index) in Zip::new((allocation, 0..)) {
                for (input, individual_input_index) in Zip::new((&req.data.inputs, 0..)) {
                    vec.push(InputBinding {
                        allocation: allocation_index,
                        device: individual_device_index,
                        input: individual_input_index
                    })
                }
            }
        }
        vec
    }
}

/// The binding of an input capability to a specific device set.
struct InputBinding {
    /// The device set holding this input capability.
    /// Index in `app.allocations`.
    allocation: usize,

    /// The individual device holding this input capability.
    /// Index in `app.allocations[self.allocation]`.
    device: usize,

    /// The specific input holding this input capability.
    /// Index in `app.allocations[self.allocation][self.device]`.
    input: usize,
}

impl InputBinding {
    /// Get the device providing the InputBinding.
    fn get_individual_device(&self, app: &MonitorApp) -> Arc<Device> {
        app.allocations[self.allocation][self.device].data.clone()
    }

    /// Get the input capability for this binding.
    fn get_input(&self, app: &MonitorApp) -> InputCapability {
        app.requirements[self.allocation].data.inputs[self.input].data.clone()
    }

    /// Update the state attached to this input binding.
    fn set_state(&self, state: &mut MonitorTaskState, value: Option<Json>) {
        state.input_state[self.allocation][self.device][self.input] = value;
    }
}

/// The state of a given condition.
struct ConditionState {
    /// `true` if the conditions were met last time the state of the
    /// inputs changed. We use this to trigger an action only when
    /// conditions were previously unmet and are now met.
    are_conditions_met: bool,
    // FIXME: In the future, the cooldown should go here.
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTaskState {
    /// The state of each trigger.
    ///
    /// Invariant: len() is the same as that of `self.app.rule`s
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    ///
    /// Use `InputBinding` to access the data.
    input_state: InputState,

    witnesses: Vec<Witness>,

    /// A clone of the code being executed.
    app: MonitorApp,
}

/// The part of the monitor used to communicate between threads.
///
/// Kept separate to help the borrow checker understand what we're
/// accessing at any time.
struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}

/// A MonitorApp currently being executed.
///
/// Each MonitorTask runs on its own thread.
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {
    /// Create a new MonitorTask.
    ///
    /// This creates the data structures and initializes watching,
    /// but the task is not launched
    fn start(app: MonitorApp) -> Sender<MonitorOp> {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.rules.len());
        for _ in &app.rules {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.rules.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();
        let (tx, rx) = channel();

        for state_index in app.iter_state_index() {
            // FIXME: We currently use `Range::any()` for simplicity.
            // However, in most cases, we should be able to look inside
            // the condition to build a better `Range`.

            // FIXME: We currently monitor all the inputs that are
            // used by this rule, even if they are not part of the
            // condition (e.g. we monitor the camera all the time even
            // if we only need to trigger when an intruder enters).
            witnesses.push(
                watcher.add(
                    &state_index.get_individual_device(&app),
                    &state_index.get_input(&app),
                    &Range::any(),
                    |data| {
                        let _ignored = tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting
                        // down, it's ok to lose messages.
                    }));
        }

        let result = tx.clone();

        let mut task = MonitorTask {
            state: MonitorTaskState {
                trigger_condition_state: trigger_condition_state,
                input_state: full_input_state,
                witnesses: witnesses,
                app: app,
            },
            comm: MonitorComm {
                tx: tx,
                rx: rx,
            }
        };

        thread::spawn(move || {
            task.run();
        });

        result
    }

    /// Execute the monitoring task.
    /// This currently expects to be executed in its own thread.
    fn run(&mut self) {
        for msg in &self.comm.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    index,
                } => {
                    // Update the state
                    index.set_state(&mut self.state, Some(data));

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.state.app.rules, &mut self.state.trigger_condition_state)) {
                        let is_met = trigger.condition.is_met(&self.state.input_state);
                        if is_met == trigger_condition_state.are_conditions_met {
                            // No change in conditions. Nothing to do.
                            continue;
                        }
                        trigger_condition_state.are_conditions_met = is_met;
                        if !is_met {
                            // Conditions were met, now they are not anymore.
                            // The next time they are met, we can trigger
                            // a new execution.
                            continue;
                        }
                        // Conditions were not met, now they are, so it is
                        // time to start executing. We copy the inputs
                        // and dispatch to a background thread

                        // FIXME: Handle cooldown.

                        trigger_condition_state.are_conditions_met = true;
                        let _ignored = self.comm.tx.send(MonitorOp::Execute {
                            state: self.state.input_state.clone(),
                            commands: trigger.execute.clone()
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    self.state.witnesses.clear();
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, index: InputBinding},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    ///
    /// Start executing the application.
    ///
    pub fn start(&mut self) {
        if self.command_sender.is_some() {
            return;
        }
        self.command_sender = Some(MonitorTask::start(self.clone()));
    }

    ///
    /// Stop the execution of the application.
    ///
    pub fn stop(&mut self) {
        match self.command_sender {
            None => {
                /* Nothing to stop */
                return;
            },
            Some(ref tx) => {
                // Shutdown the application, asynchronously.
                let _ignored = tx.send(MonitorOp::Stop);
                // Do not return.
            }
        }
        self.command_sender = None;
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> where T: Clone {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<commit_msg>Refactored the MonitorTask to make sure that watching takes places off main thread<commit_after>
#![allow(unused_variables)]
#![allow(dead_code)]

/// Basic structure of a Monitor (aka Server App, aka wtttttt)
///
/// Monitors are designed so that the FoxBox can offer a simple
/// IFTTT-style Web UX to let users write their own scripts. More
/// complex monitors can installed from the web from a master device
/// (i.e. the user's cellphone or smart tv).

use dependencies::{DeviceKind, InputCapability, OutputCapability, Device, Range, Watcher};

use std::time::Duration;
use std::collections::HashMap;
use std::sync::Arc;
use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

extern crate rustc_serialize;
use self::rustc_serialize::json::Json;

extern crate itertools;
use self::itertools::Zip;

/// A Monitor Application, i.e. an application (or a component of an
/// application) executed on the server.
///
/// Monitor applications are typically used for triggering an action
/// in reaction to an event: changing temperature when night falls,
/// ringing an alarm when a door is opened, etc.
///
/// Monitor applications are installed from a paired device. They may
/// either be part of a broader application (which can install them
/// through a web/REST API) or live on their own.
#[derive(Clone)]
struct MonitorApp {
    metadata: (), // FIXME: Authorizations, author, description, update url, version, ...

    /// `true` if the app is on, `false` otherwise.
    is_active: bool,

    /// Monitor applications have sets of requirements (e.g. "I need a
    /// camera"), which are allocated to actual resources through the
    /// UX. Re-allocating resources may be requested by the user, the
    /// foxbox, or an application, e.g. when replacing a device or
    /// upgrading the app.
    ///
    /// The position in the vector is important, as it is used to
    /// represent the instances of resources in the script.
    ///
    /// FIXME: Turn this `Vec` (and others) into a data structure in
    /// which this indexing property is built-in.
    requirements: Vec<Named<Requirement>>,

    /// For each requirement, the resources actually allocated to
    /// match the requirements. This may be 1 or more individual
    /// devices.
    ///
    /// Allocations can be done in several ways:
    ///
    /// - when entering the script through a UX (either the script or
    ///   the UX can suggest allocations);
    /// - when installing an application with a web front-end.
    allocations: Vec<Vec<Named<Arc<Device>>>>,

    /// A set of rules, stating what must be done in which circumstance.
    rules: Vec<Trigger>,

    /// Either `None` if the application is not launched, or `Some(tx)`,
    /// where `tx` is a channel used to communicate with the thread
    /// running the application.
    command_sender: Option<Sender<MonitorOp>>,
}

impl<'a> MonitorApp {
    /// Index-safe iteration through all the possible
    /// allocations/individual devices/inputs.
    fn iter_state_index(&self) -> Vec<InputBinding>
    {
        // FIXME: Several possible optimizations here, including
        // caching the vector.
        let mut vec = Vec::new();
        for (req, allocation, allocation_index) in Zip::new((&self.requirements, &self.allocations, 0..)) {
            for (individual_device, individual_device_index) in Zip::new((allocation, 0..)) {
                for (input, individual_input_index) in Zip::new((&req.data.inputs, 0..)) {
                    vec.push(InputBinding {
                        allocation: allocation_index,
                        device: individual_device_index,
                        input: individual_input_index
                    })
                }
            }
        }
        vec
    }
}

/// The binding of an input capability to a specific device set.
struct InputBinding {
    /// The device set holding this input capability.
    /// Index in `app.allocations`.
    allocation: usize,

    /// The individual device holding this input capability.
    /// Index in `app.allocations[self.allocation]`.
    device: usize,

    /// The specific input holding this input capability.
    /// Index in `app.allocations[self.allocation][self.device]`.
    input: usize,
}

impl InputBinding {
    /// Get the device providing the InputBinding.
    fn get_individual_device(&self, app: &MonitorApp) -> Arc<Device> {
        app.allocations[self.allocation][self.device].data.clone()
    }

    /// Get the input capability for this binding.
    fn get_input(&self, app: &MonitorApp) -> InputCapability {
        app.requirements[self.allocation].data.inputs[self.input].data.clone()
    }

    /// Update the state attached to this input binding.
    fn set_state(&self, state: &mut MonitorTaskState, value: Option<Json>) {
        state.input_state[self.allocation][self.device][self.input] = value;
    }
}

/// The state of a given condition.
struct ConditionState {
    /// `true` if the conditions were met last time the state of the
    /// inputs changed. We use this to trigger an action only when
    /// conditions were previously unmet and are now met.
    are_conditions_met: bool,
    // FIXME: In the future, the cooldown should go here.
}

type InputState = Vec<Vec<Vec<Option<Json>>>>;
struct MonitorTaskState {
    /// The state of each trigger.
    ///
    /// Invariant: len() is the same as that of `self.app.rule`s
    trigger_condition_state: Vec<ConditionState>,

    /// For each device set allocated, for each individual device
    /// allocated, for each input watched by the app, the latest state
    /// received.
    ///
    /// Use `InputBinding` to access the data.
    input_state: InputState,

    /// A clone of the code being executed.
    app: MonitorApp,
}

/// The part of the monitor used to communicate between threads.
///
/// Kept separate to help the borrow checker understand what we're
/// accessing at any time.
struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}

/// A MonitorApp currently being executed.
///
/// Each MonitorTask runs on its own thread.
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {

    /// Create a new MonitorTask.
    ///
    /// To initiate watching, use method `run()`.
    fn new(app: MonitorApp) -> Self {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.rules.len());
        for _ in &app.rules {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.rules.len());

        // Initialize input state.
        let mut full_input_state = Vec::with_capacity(app.requirements.len());
        for (req, allocation) in app.requirements.iter().zip(&app.allocations) {

            // State for this allocation. A single allocation may map
            // to a number of inputs (e.g. "all fire alarms").
            let mut allocation_state = Vec::with_capacity(allocation.len());
            for individual_device in allocation {
                let mut individual_device_state = Vec::with_capacity(req.data.inputs.len());
                for _ in 0 .. req.data.inputs.len() {
                    individual_device_state.push(None);
                }
                allocation_state.push(individual_device_state);
            }
            assert_eq!(allocation_state.len(), allocation.len());
            full_input_state.push(allocation_state);
        }
        assert_eq!(full_input_state.len(), app.requirements.len());

        // Start watching
        let (tx, rx) = channel();

        MonitorTask {
            state: MonitorTaskState {
                trigger_condition_state: trigger_condition_state,
                input_state: full_input_state,
                app: app,
            },
            comm: MonitorComm {
                tx: tx,
                rx: rx,
            }
        }
    }

    /// Get a channel that may be used to send commands to the task.
    fn get_command_sender(&self) -> Sender<MonitorOp> {
        self.comm.tx.clone()
    }

    /// Execute the monitoring task.
    /// This currently expects to be executed in its own thread.
    fn run(&mut self) {
        let mut watcher = Watcher::new();
        let mut witnesses = Vec::new();

        for state_index in self.state.app.iter_state_index() {
            // FIXME: We currently use `Range::any()` for simplicity.
            // However, in most cases, we should be able to look inside
            // the condition to build a better `Range`.

            // FIXME: We currently monitor all the inputs that are
            // used by this rule, even if they are not part of the
            // condition (e.g. we monitor the camera all the time even
            // if we only need to trigger when an intruder enters).
            witnesses.push(
                watcher.add(
                    &state_index.get_individual_device(&self.state.app),
                    &state_index.get_input(&self.state.app),
                    &Range::any(),
                    |data| {
                        let _ignored = self.comm.tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting
                        // down, it's ok to lose messages.
                    }));
        }

        for msg in &self.comm.rx {
            use self::MonitorOp::*;
            match msg {
                Update {
                    data,
                    index,
                } => {
                    // Update the state
                    index.set_state(&mut self.state, Some(data));

                    // Find out if we should execute triggers.
                    // FIXME: We could optimize this by finding out which triggers
                    // are tainted by the update and only rechecking these.
                    for (trigger, trigger_condition_state) in Zip::new((&self.state.app.rules, &mut self.state.trigger_condition_state)) {
                        let is_met = trigger.condition.is_met(&self.state.input_state);
                        if is_met == trigger_condition_state.are_conditions_met {
                            // No change in conditions. Nothing to do.
                            continue;
                        }
                        trigger_condition_state.are_conditions_met = is_met;
                        if !is_met {
                            // Conditions were met, now they are not anymore.
                            // The next time they are met, we can trigger
                            // a new execution.
                            continue;
                        }
                        // Conditions were not met, now they are, so it is
                        // time to start executing. We copy the inputs
                        // and dispatch to a background thread

                        // FIXME: Handle cooldown.

                        trigger_condition_state.are_conditions_met = true;
                        let _ignored = self.comm.tx.send(MonitorOp::Execute {
                            state: self.state.input_state.clone(),
                            commands: trigger.execute.clone()
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }
                },
                Execute {..} => {
                    panic!("Not implemented");
                }
                Stop => {
                    // Clean up watcher, stop the thread.
                    return;
                }
            }
        }
    }
}

enum MonitorOp {
    Update{data: Json, index: InputBinding},
    Execute{state: InputState, commands: Vec<Command>},
    Stop
}

impl MonitorApp {
    ///
    /// Start executing the application.
    ///
    pub fn start(&mut self) {
        if self.command_sender.is_some() {
            return;
        }
        let mut task = MonitorTask::new(self.clone());
        self.command_sender = Some(task.get_command_sender());
        thread::spawn(move || {
            task.run();
        });
    }

    ///
    /// Stop the execution of the application.
    ///
    pub fn stop(&mut self) {
        match self.command_sender {
            None => {
                /* Nothing to stop */
                return;
            },
            Some(ref tx) => {
                // Shutdown the application, asynchronously.
                let _ignored = tx.send(MonitorOp::Stop);
                // Do not return.
            }
        }
        self.command_sender = None;
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> where T: Clone {
    /// User-readable name.
    name: String,

    data: T,
}

/// A resource needed by this application. Typically, a definition of
/// device with some input our output capabilities.
#[derive(Clone)]
struct Requirement {
    /// The kind of resource, e.g. "a flashbulb".
    kind: DeviceKind,

    /// Input capabilities we need from the device, e.g. "the time of
    /// day", "the current temperature".
    inputs: Vec<Named<InputCapability>>,

    /// Output capabilities we need from the device, e.g. "play a
    /// sound", "set luminosity".
    outputs: Vec<Named<OutputCapability>>,

    /// Minimal number of resources required. If unspecified in the
    /// script, this is 1.
    min: u32,

    /// Maximal number of resources that may be handled. If
    /// unspecified in the script, this is the same as `min`.
    max: u32,

    // FIXME: We may need cooldown properties.
}

/// A single trigger, i.e. "when some condition becomes true, do
/// something".
#[derive(Clone)]
struct Trigger {
    /// The condition in which to execute the trigger.
    condition: Disjunction,

    /// Stuff to do once `condition` is met.
    execute: Vec<Command>,

    /// Minimal duration between two executions of the trigger.  If a
    /// duration was not picked by the developer, a reasonable default
    /// duration should be picked (e.g. 10 minutes).
    cooldown: Duration,
}

/// A disjunction (e.g. a "or") of conditions.
///
/// # Example
///
/// Door alarm #1 OR door alarm #2
#[derive(Clone)]
struct Disjunction {
    /// The disjunction is true iff any of the following conjunctions is true.
    any: Vec<Conjunction>
}

impl Disjunction {
    fn is_met(&self, input_state: &InputState) -> bool {
        panic!("Not implemented");
    }
}

/// A conjunction (e.g. a "and") of conditions.
#[derive(Clone)]
struct Conjunction {
    /// The conjunction is true iff all of the following expressions evaluate to true.
    all: Vec<Expression>
}

#[derive(Clone)]
enum Value {
    Json(Json),
    Blob{data: Arc<Vec<u8>>, mime_type: String},
}

/// An expression in the language.  Note that expressions may contain
/// inputs, which are typically asynchronous. Consequently,
/// expressions are evaluated asynchronously.
#[derive(Clone)]
enum Expression {
    Const {
        value: Value,

        /// We are dealing with real-world values, so physical units
        /// will prevent real-world accidents.
        unit: (), // FIXME: An actual unit

        /// The source for this value.  Used whenever we need to find
        /// out which sensor triggered the trigger (e.g. "where is the
        /// fire?").
        sources: Vec<usize>,
    },

    /// Dynamic values, including both actual sensors and higher-level values.
    ///
    /// # Example
    ///
    /// "Is there movement on motion detector" (may be true/false)
    ///
    /// # Example
    ///
    /// "Date of the latest motion on motion detector" (a Date)
    Input {
        /// A reference to the device used for input.
        /// This is an index in `requirements` and `allocations`.
        index: usize, // FIXME: We should use a custom type.

        /// A property to fetch (e.g. "luminosity" or "meta/latest-on").
        property: InputCapability,
    },

    /// Pure functions on values. The fact that they are pure
    /// functions is important, as it lets us find out automatically
    /// which subexpressions (including inputs) do not need to be
    /// re-evaluated.
    Function {
        function: Function,
        // FIXME: use a Box<> for now to avoid recursive type.
        arguments: Vec<Box<Expression>>
    },
}

#[derive(Clone)]
enum Function {
    // Operations on all values.
    InRange,
    OutOfRange,
    // Operations on strings
    Contains,
    NotContains,
}

/*
enum Function {
    // Operations on all values.
    Equals,
    NotEquals,

    // Operations on numbers, dates, durations.
    GreaterEq,
    Greater,
    LowerEq,
    Lower,
    Plus,
    Minus,

    // Operations on strings
    Contains,
    NotContains,

    // Etc.  FIXME: We'll need operations on dates, extracting name
    // from device, etc.
}
 */

/// Stuff to actually do. In practice, this is always a REST call.
// FIXME: Need to decide how much we wish to sandbox apps.
#[derive(Clone)]
struct Command {
    /// The resource to which this command applies,
    /// as an index in Trigger.requirements/allocations.
    destination: usize,  // FIXME: Use custom type.

    action: OutputCapability,

    arguments: HashMap<String, Option<Expression>>
}

<|endoftext|>


<commit_before>use std::f64::consts;

use serde_bytes;

use super::serialize;

#[derive(Debug, Serialize)]
enum TestEnum {
    TestUnit,
    TestNewtype(#[serde(with = "serde_bytes")] &'static [u8]),
    TestTuple(i8, u64),
    TestStruct { abc: (), def: char },
}

#[derive(Debug, Serialize)]
struct SerializeStruct {
    test_list: Vec<i32>,
    test_tuple: (String, Option<f64>),
    test_enum: TestEnum,
    test_enum_list: Vec<TestEnum>,
}

const BASIC_SERIALIZED: &[u8] = b"\x00\x02\x00\x00\x00\x00\x04\xcb\x00\x01\x03\x04\r\x03\t\
                                  test_list\x00\x03\x05\x03\x03\x03\x04\x03*\x04\xdb\x03\x05\x00\
                                  \x00\x08\x00\r\x03\ntest_tuple\x00\x03\x02\r\x03\x03foo\x07\
                                  \x18-DT\xfb!\t@\r\x03\ttest_enum\r\x03\x08TestUnit\r\x03\x0e\
                                  test_enum_list\x00\x03\x03\x01\x03\x01\r\x03\x0bTestNewtype\
                                  \x02\x03\tBSER test\x01\x03\x01\r\x03\tTestTuple\x00\x03\x02\x03*\
                                  \x06\xff\xff\xff\xff\xff\xff\xff\x7f\x01\x03\x01\r\x03\n\
                                  TestStruct\x00\x03\x02\r\x03\x03abc\n\r\x03\x03\
                                  def\r\x03\x04\xf0\x9f\x92\xa9";

#[test]
fn test_basic_serialize() {
    let to_serialize = SerializeStruct {
        test_list: vec![3, 4, 42, 987, 2 << 18],
        test_tuple: ("foo".into(), Some(consts::PI)),
        test_enum: TestEnum::TestUnit,
        test_enum_list: vec![
            TestEnum::TestNewtype(&b"BSER test"[..]),
            TestEnum::TestTuple(42, i64::max_value() as u64),
            TestEnum::TestStruct {
                abc: (),
                def: '\u{1f4a9}',
            },
        ],
    };

    let out = Vec::new();
    let out = serialize(out, to_serialize).unwrap();
    assert_eq!(out, BASIC_SERIALIZED);
}
<commit_msg>Delete lines of the form "use [a-z_]+;"<commit_after>use std::f64::consts;

use super::serialize;

#[derive(Debug, Serialize)]
enum TestEnum {
    TestUnit,
    TestNewtype(#[serde(with = "serde_bytes")] &'static [u8]),
    TestTuple(i8, u64),
    TestStruct { abc: (), def: char },
}

#[derive(Debug, Serialize)]
struct SerializeStruct {
    test_list: Vec<i32>,
    test_tuple: (String, Option<f64>),
    test_enum: TestEnum,
    test_enum_list: Vec<TestEnum>,
}

const BASIC_SERIALIZED: &[u8] = b"\x00\x02\x00\x00\x00\x00\x04\xcb\x00\x01\x03\x04\r\x03\t\
                                  test_list\x00\x03\x05\x03\x03\x03\x04\x03*\x04\xdb\x03\x05\x00\
                                  \x00\x08\x00\r\x03\ntest_tuple\x00\x03\x02\r\x03\x03foo\x07\
                                  \x18-DT\xfb!\t@\r\x03\ttest_enum\r\x03\x08TestUnit\r\x03\x0e\
                                  test_enum_list\x00\x03\x03\x01\x03\x01\r\x03\x0bTestNewtype\
                                  \x02\x03\tBSER test\x01\x03\x01\r\x03\tTestTuple\x00\x03\x02\x03*\
                                  \x06\xff\xff\xff\xff\xff\xff\xff\x7f\x01\x03\x01\r\x03\n\
                                  TestStruct\x00\x03\x02\r\x03\x03abc\n\r\x03\x03\
                                  def\r\x03\x04\xf0\x9f\x92\xa9";

#[test]
fn test_basic_serialize() {
    let to_serialize = SerializeStruct {
        test_list: vec![3, 4, 42, 987, 2 << 18],
        test_tuple: ("foo".into(), Some(consts::PI)),
        test_enum: TestEnum::TestUnit,
        test_enum_list: vec![
            TestEnum::TestNewtype(&b"BSER test"[..]),
            TestEnum::TestTuple(42, i64::max_value() as u64),
            TestEnum::TestStruct {
                abc: (),
                def: '\u{1f4a9}',
            },
        ],
    };

    let out = Vec::new();
    let out = serialize(out, to_serialize).unwrap();
    assert_eq!(out, BASIC_SERIALIZED);
}
<|endoftext|>


<commit_before>use hyper::Client;
use hyper::client::Response;
use serde_json::StreamDeserializer;
use std::io;
use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc::{Sender, channel};
use std::thread;
use super::Error;
use super::rand;
use super::serde_json;
use super::term;
use super::url;

include!(concat!(env!("OUT_DIR"), "/logs.rs"));

const PROXY_HOST: &'static str = "http://127.0.0.1:8001";

#[derive(Debug)]
struct Record {
    namespace: String,
    pod: String,
    container: String,
    color: term::color::Color,
    text: String,
}

#[derive(Default, Debug)]
pub struct Logs {
    follow: bool,
    label: Option<String>,
    namespace: Option<String>,
}

struct Pods {
    inner: Box<Iterator<Item = Pod>>,
}

impl Pods {
    pub fn new<Bytes>(follow: bool, bytes: Bytes) -> Result<Pods, Error>
        where Bytes: 'static + Iterator<Item = io::Result<u8>>
    {
        if follow {
            let s: StreamDeserializer<PodEvent, _> = StreamDeserializer::new(bytes);
            Ok(Pods { inner: Box::new(s.filter_map(|e| e.ok()).map(|e| e.object)) })
        } else {
            Ok(Pods {
                inner: Box::new(try!(serde_json::from_iter::<_, PodList>(bytes)).items.into_iter()),
            })
        }
    }
}
impl Iterator for Pods {
    type Item = Pod;
    fn next(&mut self) -> Option<Pod> {
        self.inner.next()
    }
}

impl Logs {
    pub fn new(follow: bool, label: Option<String>, namespace: Option<String>) -> Logs {
        Logs {
            follow: follow,
            label: label,
            namespace: namespace,
        }
    }

    pub fn fetch(&self) -> Result<(), Error> {
        let colors = vec![term::color::CYAN,
                          term::color::MAGENTA,
                          term::color::GREEN,
                          term::color::YELLOW,
                          term::color::BRIGHT_BLUE];
        let mut rng = rand::thread_rng();
        let (tx, rx) = channel();
        // recv records from the channel
        let mut t = term::stdout().unwrap();
        thread::spawn(move || {
            loop {
                if let Ok(Record { namespace, pod, container, color, text }) = rx.recv() {
                    t.reset().unwrap();
                    t.fg(color).unwrap();
                    write!(t, "{}/{}/{}: ", namespace, pod, container).unwrap();
                    t.reset().unwrap();
                    writeln!(t, " {}", text).unwrap();
                }
            }
        });

        let client = Client::new();
        let mut pods_endpoint = match self.namespace {
            Some(ref ns) => {
                try!(try!(url::Url::parse(PROXY_HOST))
                    .join(&format!("/api/v1/namespaces/{}/pods", ns)))
            }
            _ => try!(try!(url::Url::parse(PROXY_HOST)).join("/api/v1/pods")),

        };
        if let Some(ref label) = self.label {
            pods_endpoint.query_pairs_mut().append_pair("labelSelector", label);
        }
        if self.follow {
            pods_endpoint.query_pairs_mut().append_pair("watch", true.to_string().as_str());
        }
        let response = try!(client.get(pods_endpoint).send());

        for pod in try!(Pods::new(self.follow, response.bytes())) {
            let color = rand::sample(&mut rng, colors.clone(), 1)[0];
            for container in pod.spec.containers {
                let pxc = tx.clone();
                let this_namespace = pod.metadata.namespace.clone();
                let this_pod_name = pod.metadata.name.clone();
                let mut logs_endpoint = url::Url::parse(PROXY_HOST)
                    .unwrap()
                    .join(&format!("/api/v1/namespaces/{}/pods/{}/log",
                                   this_namespace,
                                   this_pod_name))
                    .unwrap();
                logs_endpoint.query_pairs_mut()
                    .extend_pairs(vec![("container", container.name.as_str()),
                                       ("follow", self.follow.to_string().as_str())]);
                let reader = BufReader::new(client.get(logs_endpoint).send().unwrap());

                thread::spawn(move || {
                    for l in reader.lines() {
                        if let Ok(text) = l {
                            let _ = pxc.send(Record {
                                namespace: this_namespace.clone(),
                                pod: this_pod_name.clone(),
                                container: container.name.clone(),
                                color: color,
                                text: text,
                            });
                        }
                    }
                });
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>iterator for colors<commit_after>use hyper::Client;
use hyper::client::Response;
use serde_json::StreamDeserializer;
use std::io;
use std::io::{BufRead, BufReader, Read};
use std::sync::mpsc::{Sender, channel};
use std::thread;
use super::Error;
use super::rand;
use super::serde_json;
use super::term;
use super::url;

include!(concat!(env!("OUT_DIR"), "/logs.rs"));

const PROXY_HOST: &'static str = "http://127.0.0.1:8001";

#[derive(Debug)]
struct Record {
    namespace: String,
    pod: String,
    container: String,
    color: term::color::Color,
    text: String,
}

#[derive(Default, Debug)]
pub struct Logs {
    follow: bool,
    label: Option<String>,
    namespace: Option<String>,
}

struct Pods {
    inner: Box<Iterator<Item = Pod>>,
}

impl Pods {
    pub fn new<Bytes>(follow: bool, bytes: Bytes) -> Result<Pods, Error>
        where Bytes: 'static + Iterator<Item = io::Result<u8>>
    {
        if follow {
            let s: StreamDeserializer<PodEvent, _> = StreamDeserializer::new(bytes);
            Ok(Pods { inner: Box::new(s.filter_map(|e| e.ok()).map(|e| e.object)) })
        } else {
            Ok(Pods {
                inner: Box::new(try!(serde_json::from_iter::<_, PodList>(bytes)).items.into_iter()),
            })
        }
    }
}

impl Iterator for Pods {
    type Item = Pod;
    fn next(&mut self) -> Option<Pod> {
        self.inner.next()
    }
}

struct ColorWheel {
    colors: Vec<term::color::Color>,
    rng: rand::ThreadRng,
}

impl ColorWheel {
    fn new() -> ColorWheel {
        ColorWheel {
            colors: vec![term::color::CYAN,
                         term::color::MAGENTA,
                         term::color::GREEN,
                         term::color::YELLOW,
                         term::color::BRIGHT_BLUE],
            rng: rand::thread_rng(),
        }
    }
}

impl Iterator for ColorWheel {
    type Item = term::color::Color;
    fn next(&mut self) -> Option<term::color::Color> {
        Some(rand::sample(&mut self.rng, self.colors.clone(), 1)[0])
    }
}

impl Logs {
    pub fn new(follow: bool, label: Option<String>, namespace: Option<String>) -> Logs {
        Logs {
            follow: follow,
            label: label,
            namespace: namespace,
        }
    }

    pub fn fetch(&self) -> Result<(), Error> {
        let mut colors = ColorWheel::new();
        let (tx, rx) = channel();
        let mut t = term::stdout().unwrap();
        thread::spawn(move || {
            loop {
                if let Ok(Record { namespace, pod, container, color, text }) = rx.recv() {
                    t.reset().unwrap();
                    t.fg(color).unwrap();
                    write!(t, "{}/{}/{}: ", namespace, pod, container).unwrap();
                    t.reset().unwrap();
                    writeln!(t, " {}", text).unwrap();
                }
            }
        });

        let client = Client::new();
        let mut pods_endpoint = match self.namespace {
            Some(ref ns) => {
                try!(try!(url::Url::parse(PROXY_HOST))
                    .join(&format!("/api/v1/namespaces/{}/pods", ns)))
            }
            _ => try!(try!(url::Url::parse(PROXY_HOST)).join("/api/v1/pods")),

        };
        if let Some(ref label) = self.label {
            pods_endpoint.query_pairs_mut().append_pair("labelSelector", label);
        }
        if self.follow {
            pods_endpoint.query_pairs_mut().append_pair("watch", true.to_string().as_str());
        }
        let response = try!(client.get(pods_endpoint).send());

        for pod in try!(Pods::new(self.follow, response.bytes())) {
            let color = colors.next().unwrap();
            for container in pod.spec.containers {
                let pxc = tx.clone();
                let this_namespace = pod.metadata.namespace.clone();
                let this_pod_name = pod.metadata.name.clone();
                let mut logs_endpoint = url::Url::parse(PROXY_HOST)
                    .unwrap()
                    .join(&format!("/api/v1/namespaces/{}/pods/{}/log",
                                   this_namespace,
                                   this_pod_name))
                    .unwrap();
                logs_endpoint.query_pairs_mut()
                    .extend_pairs(vec![("container", container.name.as_str()),
                                       ("follow", self.follow.to_string().as_str())]);
                let reader = BufReader::new(client.get(logs_endpoint).send().unwrap());

                thread::spawn(move || {
                    for l in reader.lines() {
                        if let Ok(text) = l {
                            let _ = pxc.send(Record {
                                namespace: this_namespace.clone(),
                                pod: this_pod_name.clone(),
                                container: container.name.clone(),
                                color: color,
                                text: text,
                            });
                        }
                    }
                });
            }
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime
//  factors of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use that value.
const NUM_FACTORS_INLINE: usize = 4;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let n_zeros = num.trailing_zeros();
    if n_zeros > 0 {
        factors.add(2, n_zeros as Exponent);
        n >>= n_zeros;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (factor, exp) = dec.pop().unwrap();

        if let Some(divisor) = find_factor(factor) {
            let mut gcd_queue = Decomposition::one();

            let quotient = factor / divisor;
            if quotient == divisor {
                gcd_queue.add(divisor, exp + 1);
            } else {
                gcd_queue.add(divisor, exp);
                gcd_queue.add(quotient, exp);
            }

            let mut non_trivial_gcd = quotient != divisor;
            while non_trivial_gcd {
                debug_assert_eq!(factor, gcd_queue.product());

                let mut tmp = Decomposition::one();
                non_trivial_gcd = false;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, exp_a) = gcd_queue.0[i];
                    let (mut b, exp_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        non_trivial_gcd = true;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, exp_a);
                    }
                    if g != 1 {
                        tmp.add(g, exp_a + exp_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, exp_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(factor, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // factor is prime
            factors.add(factor, exp);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_correctly_recombines_prior_test_failures() {
        let prior_failures = [
            // * integers with duplicate factors (ie, N.pow(M))
            4566769_u64, // == 2137.pow(2)
            2044854919485649_u64,
            18446739546814299361_u64,
            18446738440860217487_u64,
            18446736729316206481_u64,
        ];
        assert!(prior_failures.iter().all(|i| factor(*i).product() == *i));
    }

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_small_squares() {
        // factor(18446736729316206481) == 4294966441 ** 2 ; causes debug_assert fault for repeated decomposition factor in add()
        // ToDO: explain/combine with factor_18446736729316206481 and factor_18446739546814299361 tests
        assert!((1..10_000)
            .map(|i| (2 * i + 1) * (2 * i + 1))
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<commit_msg>perf/factor ~ improve factor() quotient and loop comparison (~6% time improvement)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime
//  factors of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use that value.
const NUM_FACTORS_INLINE: usize = 4;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let n_zeros = num.trailing_zeros();
    if n_zeros > 0 {
        factors.add(2, n_zeros as Exponent);
        n >>= n_zeros;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (factor, exp) = dec.pop().unwrap();

        if let Some(divisor) = find_factor(factor) {
            let mut gcd_queue = Decomposition::one();

            let quotient = factor / divisor;
            let mut trivial_gcd = quotient == divisor;
            if trivial_gcd {
                gcd_queue.add(divisor, exp + 1);
            } else {
                gcd_queue.add(divisor, exp);
                gcd_queue.add(quotient, exp);
            }

            while !trivial_gcd {
                debug_assert_eq!(factor, gcd_queue.product());

                let mut tmp = Decomposition::one();
                trivial_gcd = true;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, exp_a) = gcd_queue.0[i];
                    let (mut b, exp_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        trivial_gcd = false;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, exp_a);
                    }
                    if g != 1 {
                        tmp.add(g, exp_a + exp_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, exp_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(factor, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // factor is prime
            factors.add(factor, exp);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_correctly_recombines_prior_test_failures() {
        let prior_failures = [
            // * integers with duplicate factors (ie, N.pow(M))
            4566769_u64, // == 2137.pow(2)
            2044854919485649_u64,
            18446739546814299361_u64,
            18446738440860217487_u64,
            18446736729316206481_u64,
        ];
        assert!(prior_failures.iter().all(|i| factor(*i).product() == *i));
    }

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_small_squares() {
        // factor(18446736729316206481) == 4294966441 ** 2 ; causes debug_assert fault for repeated decomposition factor in add()
        // ToDO: explain/combine with factor_18446736729316206481 and factor_18446739546814299361 tests
        assert!((1..10_000)
            .map(|i| (2 * i + 1) * (2 * i + 1))
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std;
use std::cell::Cell;
use std::collections::HashMap;
use std::io::{Cursor, Read, Write};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
use std::str::{self, FromStr};
use time::{Duration, PreciseTime};
use proto::{self, SvCmd, UserInfo};
use net::{Message, NetworkBuffer, NetworkChannel};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

const RETRY_INTERVAL: i64 = 5;

#[derive(Copy, Clone, PartialEq, PartialOrd)]
pub enum CxnStatus {
    Disconnected = 0,
    DemoStart = 1,
    Connected = 2,
    OnServer = 3,
    Active = 4,
}

pub struct Client {
    netchannel: NetworkChannel,
    challenge: Cell<i32>,
    cxn_status: Cell<CxnStatus>,

    /// The last time this client sent a connection request to the server.
    cxn_time: Cell<Option<PreciseTime>>,
    userinfo: UserInfo,
}

impl Client {
    /// Create a new `Client` by initiating a connection to `server`. The client
    /// will request a challenge from the server and then begin normal operation.
    pub fn connect<A>(server: A) -> Client
        where A: ToSocketAddrs
    {

        let client = Client {
            netchannel: NetworkChannel::new(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1),
                                                              proto::PORT_SERVER),
                                            proto::PORT_CLIENT),
            challenge: Cell::new(0),
            userinfo: UserInfo::default(),
            cxn_status: Cell::new(CxnStatus::Disconnected),
            cxn_time: Cell::new(None),
        };

        client.netchannel.out_of_band("getchallenge\n".as_bytes());
        client
    }

    /// Sends a connection message to the server.
    ///
    /// Connection messages are out-band-messages of the form:
    ///
    /// ```
    /// connect <proto> <qport> <challenge> <userinfo>
    /// ```
    ///
    /// If all goes well, the server will reply with an out-of-band message
    /// containing a single 'j'.
    pub fn send_connect(&self) {
        self.netchannel.out_of_band(format!("connect {} {} {} \"{}\"",
                                            proto::VERSION,
                                            27001,
                                            self.challenge.get(),
                                            self.userinfo.serialize())
                                        .as_bytes());
        self.cxn_time.set(Some(PreciseTime::now()));
    }

    pub fn retry_connect(&self) {
        match self.cxn_time.get() {
            // Has it been 5 seconds since last connection attempt?
            Some(x) if x.to(PreciseTime::now()) > Duration::seconds(RETRY_INTERVAL) => {
                debug!("Five seconds elapsed, retrying...");
                self.send_connect();
            }

            _ => (),
        }
    }

    pub fn read_packets(&self) {
        while let Some(msg) = self.netchannel.process() {
            match msg {
                Message::InBand(mut msg) => self.parse_msg(&mut *msg),
                Message::OutOfBand(mut msg) => self.proc_outofband(&mut *msg),
            }
        }
    }

    pub fn parse_msg(&self, msg: &mut NetworkBuffer) {
        loop {
            use num::FromPrimitive;

            let first = msg.read_u8().unwrap();

            if first == std::u8::MAX {
                // msg_readcount++
                break;
            }

            let cmd: SvCmd = match FromPrimitive::from_u8(first) {
                Some(c) => c,
                None => break,
            };

            match cmd {
                SvCmd::ServerData => self.parse_serverdata(msg),
                _ => panic!("No handler for {:?}", cmd),
            };
        }
    }

    /// Parse data sent by the server in a SvCmd::ServerData message.
    ///
    /// see Quake/QW/client/cl_parse.c:525
    ///
    /// Server data is sent in the following format:
    /// ```
    /// proto version: u32
    /// server count: u32
    /// game directory: null-terminated string
    /// player number: u8
    /// level name: null-terminated string
    /// gravity: f32
    /// max speed: f32
    /// max spec speed: f32
    /// acceleration: f32
    /// air acceleration: f32
    /// water acceleration: f32
    /// friction: f32
    /// water friction: f32
    /// entity gravity: f32
    /// ```
    pub fn parse_serverdata(&self, msg: &mut NetworkBuffer) {
        let proto = msg.read_u32::<LittleEndian>().unwrap();

        if proto != proto::VERSION {
            // TODO: allow demo playback on versions 26-29
            // otherwise end the game
            panic!("Bad version handler unimplemented");
        }

        let servcount = msg.read_u32::<LittleEndian>().unwrap();

        let mut gamedir_bytes: Vec<u8> = Vec::new();
        loop {
            match msg.read_u8().unwrap() {
                0 => break,
                c => gamedir_bytes.push(c),
            }
        }
        let gamedir_str = String::from_utf8(gamedir_bytes).unwrap();

        // TODO: if current game dir differs, do host_writeconfig
    }

    pub fn proc_outofband(&self, msg: &mut NetworkBuffer) {
        match msg.read_u8().unwrap() as char {
            'c' => {
                // challenge
                debug!("Received challenge from server");
                let mut challenge_bytes = Vec::new();
                msg.read_to_end(&mut challenge_bytes);

                let challenge_str = match str::from_utf8(&challenge_bytes) {
                    Ok(s) => s,
                    Err(why) => {
                        warn!("Bad challenge from server.");
                        ""
                    }
                };

                debug!("{:?}", challenge_str);

                let challenge = match i32::from_str(&challenge_str) {
                    Ok(n) => n,
                    Err(why) => {
                        warn!("Bad challenge from server ({}): \"{}\"", why, challenge_str);
                        0
                    }
                };

                self.challenge.set(challenge);
                self.send_connect();
            }

            'j' => {
                // connection
                if self.cxn_status.get() >= CxnStatus::Connected {
                    return;
                }

                debug!("Server accepted connection request");
                self.cxn_status.set(CxnStatus::Connected);

                let mut msg: Vec<u8> = Vec::new();
                let mut cursor = Cursor::new(msg);
                cursor.write("new".as_bytes()).unwrap();
                cursor.write_u8(0).unwrap();
            }

            'k' => {
                // ping
                debug!("Received ping");
                self.netchannel.out_of_band(&['l' as u8, 0]);
            }

            _ => panic!("Unrecognized out-of-band message"),
        }
    }

    pub fn get_cxn_status(&self) -> CxnStatus {
        self.cxn_status.get()
    }
}
<commit_msg>Send first client message on connect<commit_after>// Copyright © 2016 Cormac O'Brien
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std;
use std::cell::Cell;
use std::collections::HashMap;
use std::io::{Cursor, Read, Write};
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs, UdpSocket};
use std::str::{self, FromStr};
use time::{Duration, PreciseTime};
use proto::{self, ClCmd, SvCmd, UserInfo};
use net::{Message, NetworkBuffer, NetworkChannel};
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

const RETRY_INTERVAL: i64 = 5;

#[derive(Copy, Clone, PartialEq, PartialOrd)]
pub enum CxnStatus {
    Disconnected = 0,
    DemoStart = 1,
    Connected = 2,
    OnServer = 3,
    Active = 4,
}

pub struct Client {
    netchannel: NetworkChannel,
    challenge: Cell<i32>,
    cxn_status: Cell<CxnStatus>,

    /// The last time this client sent a connection request to the server.
    cxn_time: Cell<Option<PreciseTime>>,
    userinfo: UserInfo,
}

impl Client {
    /// Create a new `Client` by initiating a connection to `server`. The client
    /// will request a challenge from the server and then begin normal operation.
    pub fn connect<A>(server: A) -> Client
        where A: ToSocketAddrs
    {

        let client = Client {
            netchannel: NetworkChannel::new(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1),
                                                              proto::PORT_SERVER),
                                            proto::PORT_CLIENT),
            challenge: Cell::new(0),
            userinfo: UserInfo::default(),
            cxn_status: Cell::new(CxnStatus::Disconnected),
            cxn_time: Cell::new(None),
        };

        client.netchannel.out_of_band("getchallenge\n".as_bytes());
        client
    }

    /// Sends a connection message to the server.
    ///
    /// Connection messages are out-band-messages of the form:
    ///
    /// ```
    /// connect <proto> <qport> <challenge> <userinfo>
    /// ```
    ///
    /// If all goes well, the server will reply with an out-of-band message
    /// containing a single 'j'.
    pub fn send_connect(&self) {
        self.netchannel.out_of_band(format!("connect {} {} {} \"{}\"",
                                            proto::VERSION,
                                            27001,
                                            self.challenge.get(),
                                            self.userinfo.serialize())
                                        .as_bytes());
        self.cxn_time.set(Some(PreciseTime::now()));
    }

    pub fn retry_connect(&self) {
        match self.cxn_time.get() {
            // Has it been 5 seconds since last connection attempt?
            Some(x) if x.to(PreciseTime::now()) > Duration::seconds(RETRY_INTERVAL) => {
                debug!("Five seconds elapsed, retrying...");
                self.send_connect();
            }

            _ => (),
        }
    }

    pub fn read_packets(&self) {
        while let Some(msg) = self.netchannel.process() {
            match msg {
                Message::InBand(mut msg) => self.parse_msg(&mut *msg),
                Message::OutOfBand(mut msg) => self.proc_outofband(&mut *msg),
            }
        }
    }

    pub fn parse_msg(&self, msg: &mut NetworkBuffer) {
        loop {
            use num::FromPrimitive;

            let first = msg.read_u8().unwrap();

            if first == std::u8::MAX {
                // msg_readcount++
                break;
            }

            let cmd: SvCmd = match FromPrimitive::from_u8(first) {
                Some(c) => c,
                None => break,
            };

            match cmd {
                SvCmd::ServerData => self.parse_serverdata(msg),
                _ => panic!("No handler for {:?}", cmd),
            };
        }
    }

    /// Parse data sent by the server in a SvCmd::ServerData message.
    ///
    /// see Quake/QW/client/cl_parse.c:525
    ///
    /// Server data is sent in the following format:
    /// ```
    /// proto version: u32
    /// server count: u32
    /// game directory: null-terminated string
    /// player number: u8
    /// level name: null-terminated string
    /// gravity: f32
    /// max speed: f32
    /// max spec speed: f32
    /// acceleration: f32
    /// air acceleration: f32
    /// water acceleration: f32
    /// friction: f32
    /// water friction: f32
    /// entity gravity: f32
    /// ```
    pub fn parse_serverdata(&self, msg: &mut NetworkBuffer) {
        let proto = msg.read_u32::<LittleEndian>().unwrap();

        if proto != proto::VERSION {
            // TODO: allow demo playback on versions 26-29
            // otherwise end the game
            panic!("Bad version handler unimplemented");
        }

        let servcount = msg.read_u32::<LittleEndian>().unwrap();

        let mut gamedir_bytes: Vec<u8> = Vec::new();
        loop {
            match msg.read_u8().unwrap() {
                0 => break,
                c => gamedir_bytes.push(c),
            }
        }
        let gamedir_str = String::from_utf8(gamedir_bytes).unwrap();

        // TODO: if current game dir differs, do host_writeconfig
    }

    pub fn proc_outofband(&self, msg: &mut NetworkBuffer) {
        match msg.read_u8().unwrap() as char {
            'c' => {
                // challenge
                debug!("Received challenge from server");
                let mut challenge_bytes = Vec::new();
                msg.read_to_end(&mut challenge_bytes);

                let challenge_str = match str::from_utf8(&challenge_bytes) {
                    Ok(s) => s,
                    Err(why) => {
                        warn!("Bad challenge from server.");
                        ""
                    }
                };

                debug!("{:?}", challenge_str);

                let challenge = match i32::from_str(&challenge_str) {
                    Ok(n) => n,
                    Err(why) => {
                        warn!("Bad challenge from server ({}): \"{}\"", why, challenge_str);
                        0
                    }
                };

                self.challenge.set(challenge);
                self.send_connect();
            }

            'j' => {
                // connection
                if self.cxn_status.get() >= CxnStatus::Connected {
                    return;
                }

                debug!("Server accepted connection request");
                self.cxn_status.set(CxnStatus::Connected);

                let mut msg: Vec<u8> = Vec::new();
                let mut cursor = Cursor::new(msg);
                cursor.write_u8(ClCmd::StringCmd as u8).unwrap();
                cursor.write("new".as_bytes()).unwrap();
                cursor.write_u8(0).unwrap();
                self.netchannel.transmit(cursor.get_ref());
            }

            'k' => {
                // ping
                debug!("Received ping");
                self.netchannel.out_of_band(&['l' as u8, 0]);
            }

            _ => panic!("Unrecognized out-of-band message"),
        }
    }

    pub fn get_cxn_status(&self) -> CxnStatus {
        self.cxn_status.get()
    }
}
<|endoftext|>


<commit_before>extern crate itertools;

use std::collections::{HashSet, HashMap};
use std::fmt;
use itertools::Itertools;

struct Puzzle<'a> {
    all_tkns: Vec<String>,
    all_chars: &'a str,
    char_dig: &'a mut Vec<(char, u8)>,
    leading_zeroes: &'a [char],
}

impl<'a> fmt::Debug for Puzzle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "all_tkns: {:?}, all_chars: {:?}, char_dig: {:?}, leading_zeroes: {:?}",
            self.all_tkns,
            self.all_chars,
            self.char_dig,
            self.leading_zeroes
        )
    }
}

impl<'a> Puzzle<'a> {
    pub fn new(
        all_tkns: Vec<String>,
        chars: &'a str,
        char_dig: &'a mut Vec<(char, u8)>,
        leading_zeroes: &'a [char],
    ) -> Puzzle<'a> {
        Puzzle {
            all_tkns: all_tkns,
            all_chars: chars,
            char_dig: char_dig,
            leading_zeroes: leading_zeroes,
        }
    }

    pub fn assign_letter(&mut self, letter: char, digit: u8) -> bool {
        if self.leading_zeroes
            .iter()
            .find(|&&c| c == letter && digit == 0)
            .is_some() || self.char_dig.iter().find(|&&(_, d)| digit == d).is_some()
        {
            return false;
        }

        self.char_dig.push((letter, digit));

        true
    }

    pub fn puzzle_solved(&self) -> bool {
        return self.is_combination_alphametic();
    }

    pub fn unassign_letter(&mut self, letter: char, digit: u8) {
        if let Some(idx) = self.char_dig.iter().position(
            |&(x, y)| x == letter && digit == y,
        )
        {
            self.char_dig.remove(idx);
        }
    }
    pub fn find_solution(&mut self, letter_to_assign: &str, carry: i32) -> bool {
        if letter_to_assign.len() == 0 {
            return self.puzzle_solved();
        }

        for d in 0..10 {
            if self.assign_letter(letter_to_assign.chars().take(1).next().unwrap(), d) {
                if self.find_solution(&letter_to_assign[1..], 0) {
                    return true;
                }
                self.unassign_letter(letter_to_assign.chars().take(1).next().unwrap(), d);
            }
        }
        return false;
    }

    fn is_combination_alphametic(&self) -> bool {
        let result = self.str_to_num(self.all_tkns.last().unwrap(), self.char_dig);
        if result.is_none() {
            return false;
        }

        let mut num = 0;
        for token in &self.all_tkns[..self.all_tkns.len() - 1] {
            let rslt = self.str_to_num(&*token, self.char_dig);
            if rslt.is_none() {
                return false;
            }
            num += rslt.unwrap();
        }

        result.unwrap() == num
    }

    fn str_to_num(&self, val: &str, lnums_slice: &[(char, u8)]) -> Option<u32> {
        let mut num = 0;
        let mut val_slice = val;
        let letter_to_digit_map = lnums_slice.iter().cloned().collect::<HashMap<_, _>>();

        if let Some(l) = val.chars().take(1).next() {
            if l != '_' && letter_to_digit_map[&l] == 0 {
                return None;
            }
        }
        for letter in val.chars() {
            let mut digit = 0;
            if letter == '_' {
                digit = 0;
            } else {
                digit = letter_to_digit_map[&letter];
            }
            num += 10u32.pow(val_slice.len() as u32 - 1) * digit as u32;
            val_slice = &val_slice[1..];
        }

        Some(num)
    }
}

fn normalize_tokens(tkns: &mut [String]) {
    let mut tkn_max_lgth = tkns[0].len();
    if let Some(max) = tkns.iter_mut().max_by(|x, y| x.len().cmp(&y.len())) {
        tkn_max_lgth = max.len();
    }
    for tkn in tkns.iter_mut() {
        if tkn.len() < tkn_max_lgth {
            let mut padded_tkn = "_".repeat(tkn_max_lgth - tkn.len());
            padded_tkn.extend(tkn.chars());
            *tkn = padded_tkn;
        }
    }
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let mut leading_zero_letters = left_tkns
        .iter()
        .map(|s| s.chars().take(1).next().unwrap())
        .unique()
        .collect::<Vec<_>>();
    leading_zero_letters.push(result.chars().take(1).next().unwrap());

    let leading_zero_letters = leading_zero_letters
        .into_iter()
        .collect::<HashSet<_>>()
        .iter()
        .map(|&x| x)
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let mut all_tkns = left_tkns.iter().map(|x| x.to_string()).collect::<Vec<_>>();
    all_tkns.push(result.to_string());

    normalize_tokens(all_tkns.as_mut_slice());

    let mut char_dig = Vec::new();
    let mut puzzle = Puzzle::new(all_tkns, &all_chars, &mut char_dig, &leading_zero_letters);

    if puzzle.find_solution(puzzle.all_chars, 0) {
        return Some(
            puzzle
                .char_dig
                .iter()
                .map(|&(x, y)| (x, y))
                .collect::<HashMap<_, _>>(),
        );
    }

    None
}
<commit_msg>rust: Some refactoring to speed up backtracking algo<commit_after>extern crate itertools;

use std::collections::{HashMap, HashSet};
use std::fmt;
use itertools::Itertools;

struct Puzzle<'a> {
    left_to_right_data: &'a Vec<(String, char)>,
    all_chars: &'a str,
    char_dig: &'a mut Vec<(char, u8)>,
    leading_zeroes: &'a [char],
}

impl<'a> fmt::Debug for Puzzle<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "left_to_right_data: {:?}, all_chars: {:?}, char_dig: {:?}, leading_zeroes: {:?}",
            self.left_to_right_data,
            self.all_chars,
            self.char_dig,
            self.leading_zeroes
        )
    }
}

impl<'a> Puzzle<'a> {
    pub fn new(
        left_to_right_data: &'a Vec<(String, char)>,
        chars: &'a str,
        char_dig: &'a mut Vec<(char, u8)>,
        leading_zeroes: &'a [char],
    ) -> Puzzle<'a> {
        Puzzle {
            left_to_right_data: left_to_right_data,
            all_chars: chars,
            char_dig: char_dig,
            leading_zeroes: leading_zeroes,
        }
    }

    pub fn assign_letter(&mut self, letter: char, digit: u8) -> bool {
        if self.leading_zeroes
            .iter()
            .find(|&&c| c == letter && digit == 0)
            .is_some() || self.char_dig.iter().find(|&&(_, d)| digit == d).is_some()
        {
            return false;
        }

        self.char_dig.push((letter, digit));

        true
    }

    pub fn unassign_letter(&mut self, letter: char, digit: u8) {
        if let Some(idx) = self.char_dig
            .iter()
            .position(|&(x, y)| x == letter && digit == y)
        {
            self.char_dig.remove(idx);
        }
    }

    pub fn find_solution(&mut self, carry: i32) -> bool {
        println!("puzzle: {:?}", *self);
        // if letter_to_assign.len() == 0 {
        //     return false;
        // }

        // for d in 0..10 {
        //     if self.assign_letter(letter_to_assign.chars().take(1).next().unwrap(), d) {
        //         if self.find_solution(0) {
        //             return true;
        //         }
        //         self.unassign_letter(letter_to_assign.chars().take(1).next().unwrap(), d);
        //     }
        // }
        // return false;
        false
    }
}

fn normalize_tokens(tkns: &mut [String], max_len: usize) {
    for tkn in tkns.iter_mut() {
        if tkn.len() < max_len {
            let mut padded_tkn = "_".repeat(max_len - tkn.len());
            padded_tkn.extend(tkn.chars());
            *tkn = padded_tkn;
        }
    }
}

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let mut leading_zero_letters = left_tkns
        .iter()
        .map(|s| s.chars().take(1).next().unwrap())
        .unique()
        .collect::<Vec<_>>();
    leading_zero_letters.push(result.chars().take(1).next().unwrap());

    let leading_zero_letters = leading_zero_letters
        .into_iter()
        .collect::<HashSet<_>>()
        .iter()
        .map(|&x| x)
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let mut left_tkns = left_tkns.iter().map(|x| x.to_string()).collect::<Vec<_>>();

    normalize_tokens(left_tkns.as_mut_slice(), result.len());

    let mut char_dig = Vec::new();
    let mut left_letters = &group_add_letter_togheter(&left_tkns);

    let mut puzzle = Puzzle::new(
        &left_letters
            .iter()
            .zip(result.chars())
            .collect::<Vec<(_, _)>>(),
        &all_chars,
        &mut char_dig,
        &leading_zero_letters,
    );

    if puzzle.find_solution(0) {
        return Some(
            puzzle
                .char_dig
                .iter()
                .map(|&(x, y)| (x, y))
                .collect::<HashMap<_, _>>(),
        );
    }

    None
}

fn group_add_letter_togheter<'a>(left_tkns: &'a [String]) -> Vec<String> {
    let mut output = Vec::new();
    for i in 0..left_tkns[0].len() {
        let letters = left_tkns.iter().fold(String::new(), |mut acc, tkn| {
            if let Some(l) = tkn.chars().skip(i).take(1).next() {
                acc.push(l);
            }
            acc
        });

        output.push(letters);
    }
    output
}
<|endoftext|>