<commit_before>#![allow(unused_mut, unused_variables)]

use {Result, Tape, Value, Walue};

/// An anchor.
#[derive(Clone, Debug)]
pub enum Anchor {
    /// Format 1.
    Format1(Anchor1),
    /// Format 2.
    Format2(Anchor2),
    /// Format 3.
    Format3(Anchor3),
}

table! {
    #[doc = "An anchor in format 1."]
    #[derive(Copy)]
    pub Anchor1 { // AnchorFormat1
        format (u16) = { 1 }, // AnchorFormat
        x      (i16), // XCoordinate
        y      (i16), // YCoordinate
    }
}

table! {
    #[doc = "An anchor in format 2."]
    #[derive(Copy)]
    pub Anchor2 { // AnchorFormat2
        format (u16) = { 2 }, // AnchorFormat
        x      (i16), // XCoordinate
        y      (i16), // YCoordinate
        index  (u16), // AnchorPoint
    }
}

table! {
    @position
    #[doc = "An anchor in format 3."]
    pub Anchor3 { // AnchorFormat3
        format          (u16) = { 3 }, // AnchorFormat
        x               (i16), // XCoordinate
        y               (i16), // YCoordinate
        device_x_offset (u16), // XDeviceTable
        device_y_offset (u16), // YDeviceTable

        device_x (Option<Device>) |this, tape, position| {
            jump_take_maybe!(tape, position, this.device_x_offset)
        },

        device_y (Option<Device>) |this, tape, position| {
            jump_take_maybe!(tape, position, this.device_y_offset)
        },
    }
}

table! {
    @define
    #[doc = "A device table."]
    pub Device { // Device
        start_size   (u16     ), // StartSize
        end_size     (u16     ), // EndSize
        delta_format (u16     ), // DeltaFormat
        delta_data   (Vec<u16>), // DeltaValue
    }
}

table! {
    @define
    #[doc = "An entry-exit record."]
    pub Gesture { // EntryExitRecord
        entry_offset (u16   ), // EntryAnchor
        exit_offset  (u16   ), // ExitAnchor
        entry        (Anchor),
        exit         (Anchor),
    }
}

table! {
    @define
    #[doc = "A single value."]
    pub Single { // ValueRecord
        x_placement               (Option<i16>   ), // XPlacement
        y_placement               (Option<i16>   ), // YPlacement
        x_advance                 (Option<i16>   ), // XAdvance
        y_advance                 (Option<i16>   ), // YAdvance
        device_x_placement_offset (Option<u16>   ), // XPlaDevice
        device_y_placement_offset (Option<u16>   ), // YPlaDevice
        device_x_advance_offset   (Option<u16>   ), // XAdvDevice
        device_y_advance_offset   (Option<u16>   ), // YAdvDevice
        device_x_placement        (Option<Device>),
        device_y_placement        (Option<Device>),
        device_x_advance          (Option<Device>),
        device_y_advance          (Option<Device>),
    }
}

table! {
    @define
    #[doc = "A value pair."]
    pub Pair { // PairValueRecord
        value1 (Single), // Value1
        value2 (Single), // Value2
    }
}

table! {
    @define
    #[doc = "A set of value pairs."]
    pub PairSet { // PairSet
        count   (u16      ), // PairValueCount
        records (Vec<Pair>), // PairValueRecord
    }
}

flags! {
    #[doc = "Value flags."]
    pub ValueFlags(u16) {
        0b0000_0000_0000_0001 => has_x_placement,
        0b0000_0000_0000_0010 => has_y_placement,
        0b0000_0000_0000_0100 => has_x_advance,
        0b0000_0000_0000_1000 => has_y_advance,
        0b0000_0000_0001_0000 => has_device_x_placement,
        0b0000_0000_0010_0000 => has_device_y_placement,
        0b0000_0000_0100_0000 => has_device_x_advance,
        0b0000_0000_1000_0000 => has_device_y_advance,
        0b1111_1111_0000_0000 => is_invalid,
    }
}

impl Value for Anchor {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => Anchor::Format1(try!(tape.take())),
            2 => Anchor::Format2(try!(tape.take())),
            3 => Anchor::Format3(try!(tape.take())),
            _ => raise!("found an unknown format of the anchor table"),
        })
    }
}

impl Value for Device {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        let start_size = try!(tape.take());
        let end_size = try!(tape.take());
        if start_size > end_size {
            raise!("found a malformed device table");
        }
        let delta_format = try!(tape.take());
        if delta_format == 0 || delta_format > 3 {
            raise!("found an unknow format of the device table");
        }
        let count = (end_size - start_size) as usize + 1;
        let bit_count = (1 << delta_format as usize) * count;
        let short_count = (bit_count + 16 - bit_count % 16) >> 4;
        let delta_data = try!(tape.take_given(short_count));
        Ok(Device {
            start_size: start_size,
            end_size: end_size,
            delta_format: delta_format,
            delta_data: delta_data,
        })
    }
}

impl Walue<u64> for Gesture {
    fn read<T: Tape>(tape: &mut T, position: u64) -> Result<Self> {
        let entry_offset = try!(tape.take());
        let exit_offset = try!(tape.take());
        let entry = jump_take!(@unwrap tape, position, entry_offset);
        let exit = jump_take!(@unwrap tape, position, exit_offset);
        Ok(Gesture {
            entry_offset: entry_offset,
            exit_offset: exit_offset,
            entry: entry,
            exit: exit,
        })
    }
}

impl Walue<(u64, ValueFlags, ValueFlags)> for Pair {
    #[inline]
    fn read<T: Tape>(tape: &mut T, (position, flags1, flags2): (u64, ValueFlags, ValueFlags))
                     -> Result<Self> {

        Ok(Pair {
            value1: try!(tape.take_given((position, flags1))),
            value2: try!(tape.take_given((position, flags2))),
        })
    }
}

impl Walue<(u64, ValueFlags, ValueFlags)> for PairSet {
    fn read<T: Tape>(tape: &mut T, parameter: (u64, ValueFlags, ValueFlags)) -> Result<Self> {
        let count = try!(tape.take());
        let mut records = Vec::with_capacity(count as usize);
        for _ in 0..(count as usize) {
            records.push(try!(tape.take_given(parameter)));
        }
        Ok(PairSet { count: count, records: records })
    }
}

impl Walue<(u64, ValueFlags)> for Single {
    fn read<T: Tape>(tape: &mut T, (position, flags): (u64, ValueFlags)) -> Result<Self> {
        macro_rules! take(
            ($flag:ident) => (if flags.$flag() { Some(try!(tape.take())) } else { None });
        );
        let x_placement = take!(has_x_placement);
        let y_placement = take!(has_y_placement);
        let x_advance = take!(has_x_advance);
        let y_advance = take!(has_y_advance);
        let device_x_placement_offset = take!(has_device_x_placement);
        let device_y_placement_offset = take!(has_device_y_placement);
        let device_x_advance_offset = take!(has_device_x_advance);
        let device_y_advance_offset = take!(has_device_y_advance);
        macro_rules! take(
            ($offset:ident) => (
                match $offset {
                    Some(offset) => Some(jump_take!(@unwrap tape, position, offset)),
                    _ => None,
                }
            );
        );
        let device_x_placement = take!(device_x_placement_offset);
        let device_y_placement = take!(device_y_placement_offset);
        let device_x_advance = take!(device_x_advance_offset);
        let device_y_advance = take!(device_y_advance_offset);
        Ok(Single {
            x_placement: x_placement,
            y_placement: y_placement,
            x_advance: x_advance,
            y_advance: y_advance,
            device_x_placement_offset: device_x_placement_offset,
            device_y_placement_offset: device_y_placement_offset,
            device_x_advance_offset: device_x_advance_offset,
            device_y_advance_offset: device_y_advance_offset,
            device_x_placement: device_x_placement,
            device_y_placement: device_y_placement,
            device_x_advance: device_x_advance,
            device_y_advance: device_y_advance,
        })
    }
}
<commit_msg>Make a cosmetic adjustment<commit_after>#![allow(unused_mut, unused_variables)]

use {Result, Tape, Value, Walue};

/// An anchor.
#[derive(Clone, Debug)]
pub enum Anchor {
    /// Format 1.
    Format1(Anchor1),
    /// Format 2.
    Format2(Anchor2),
    /// Format 3.
    Format3(Anchor3),
}

table! {
    #[doc = "An anchor in format 1."]
    #[derive(Copy)]
    pub Anchor1 { // AnchorFormat1
        format (u16) = { 1 }, // AnchorFormat
        x      (i16), // XCoordinate
        y      (i16), // YCoordinate
    }
}

table! {
    #[doc = "An anchor in format 2."]
    #[derive(Copy)]
    pub Anchor2 { // AnchorFormat2
        format (u16) = { 2 }, // AnchorFormat
        x      (i16), // XCoordinate
        y      (i16), // YCoordinate
        index  (u16), // AnchorPoint
    }
}

table! {
    @position
    #[doc = "An anchor in format 3."]
    pub Anchor3 { // AnchorFormat3
        format          (u16) = { 3 }, // AnchorFormat
        x               (i16), // XCoordinate
        y               (i16), // YCoordinate
        device_x_offset (u16), // XDeviceTable
        device_y_offset (u16), // YDeviceTable

        device_x (Option<Device>) |this, tape, position| {
            jump_take_maybe!(tape, position, this.device_x_offset)
        },

        device_y (Option<Device>) |this, tape, position| {
            jump_take_maybe!(tape, position, this.device_y_offset)
        },
    }
}

table! {
    @define
    #[doc = "A device table."]
    pub Device { // Device
        start_size   (u16     ), // StartSize
        end_size     (u16     ), // EndSize
        delta_format (u16     ), // DeltaFormat
        delta_data   (Vec<u16>), // DeltaValue
    }
}

table! {
    @define
    #[doc = "An entry-exit record."]
    pub Gesture { // EntryExitRecord
        entry_offset (u16   ), // EntryAnchor
        exit_offset  (u16   ), // ExitAnchor
        entry        (Anchor),
        exit         (Anchor),
    }
}

table! {
    @define
    #[doc = "A single value."]
    pub Single { // ValueRecord
        x_placement               (Option<i16>   ), // XPlacement
        y_placement               (Option<i16>   ), // YPlacement
        x_advance                 (Option<i16>   ), // XAdvance
        y_advance                 (Option<i16>   ), // YAdvance
        device_x_placement_offset (Option<u16>   ), // XPlaDevice
        device_y_placement_offset (Option<u16>   ), // YPlaDevice
        device_x_advance_offset   (Option<u16>   ), // XAdvDevice
        device_y_advance_offset   (Option<u16>   ), // YAdvDevice
        device_x_placement        (Option<Device>),
        device_y_placement        (Option<Device>),
        device_x_advance          (Option<Device>),
        device_y_advance          (Option<Device>),
    }
}

table! {
    @define
    #[doc = "A value pair."]
    pub Pair { // PairValueRecord
        value1 (Single), // Value1
        value2 (Single), // Value2
    }
}

table! {
    @define
    #[doc = "A set of value pairs."]
    pub PairSet { // PairSet
        count   (u16      ), // PairValueCount
        records (Vec<Pair>), // PairValueRecord
    }
}

flags! {
    #[doc = "Value flags."]
    pub ValueFlags(u16) {
        0b0000_0000_0000_0001 => has_x_placement,
        0b0000_0000_0000_0010 => has_y_placement,
        0b0000_0000_0000_0100 => has_x_advance,
        0b0000_0000_0000_1000 => has_y_advance,
        0b0000_0000_0001_0000 => has_device_x_placement,
        0b0000_0000_0010_0000 => has_device_y_placement,
        0b0000_0000_0100_0000 => has_device_x_advance,
        0b0000_0000_1000_0000 => has_device_y_advance,
        0b1111_1111_0000_0000 => is_invalid,
    }
}

impl Value for Anchor {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        Ok(match try!(tape.peek::<u16>()) {
            1 => Anchor::Format1(try!(tape.take())),
            2 => Anchor::Format2(try!(tape.take())),
            3 => Anchor::Format3(try!(tape.take())),
            _ => raise!("found an unknown format of the anchor table"),
        })
    }
}

impl Value for Device {
    fn read<T: Tape>(tape: &mut T) -> Result<Self> {
        let start_size = try!(tape.take());
        let end_size = try!(tape.take());
        if start_size > end_size {
            raise!("found a malformed device table");
        }
        let delta_format = try!(tape.take());
        if delta_format == 0 || delta_format > 3 {
            raise!("found an unknow format of the device table");
        }
        let count = (end_size - start_size) as usize + 1;
        let bit_count = (1 << delta_format as usize) * count;
        let short_count = (bit_count + 16 - bit_count % 16) >> 4;
        let delta_data = try!(tape.take_given(short_count));
        Ok(Device {
            start_size: start_size,
            end_size: end_size,
            delta_format: delta_format,
            delta_data: delta_data,
        })
    }
}

impl Walue<u64> for Gesture {
    fn read<T: Tape>(tape: &mut T, position: u64) -> Result<Self> {
        let entry_offset = try!(tape.take());
        let exit_offset = try!(tape.take());
        let entry = jump_take!(@unwrap tape, position, entry_offset);
        let exit = jump_take!(@unwrap tape, position, exit_offset);
        Ok(Gesture {
            entry_offset: entry_offset,
            exit_offset: exit_offset,
            entry: entry,
            exit: exit,
        })
    }
}

impl Walue<(u64, ValueFlags, ValueFlags)> for Pair {
    #[inline]
    fn read<T: Tape>(tape: &mut T, (position, flags1, flags2): (u64, ValueFlags, ValueFlags))
                     -> Result<Self> {

        Ok(Pair {
            value1: try!(tape.take_given((position, flags1))),
            value2: try!(tape.take_given((position, flags2))),
        })
    }
}

impl Walue<(u64, ValueFlags, ValueFlags)> for PairSet {
    fn read<T: Tape>(tape: &mut T, parameter: (u64, ValueFlags, ValueFlags)) -> Result<Self> {
        let count = try!(tape.take());
        let mut records = Vec::with_capacity(count as usize);
        for _ in 0..(count as usize) {
            records.push(try!(tape.take_given(parameter)));
        }
        Ok(PairSet { count: count, records: records })
    }
}

impl Walue<(u64, ValueFlags)> for Single {
    fn read<T: Tape>(tape: &mut T, (position, flags): (u64, ValueFlags)) -> Result<Self> {
        macro_rules! take(
            ($flag:ident) => (if flags.$flag() { Some(try!(tape.take())) } else { None });
        );
        let x_placement = take!(has_x_placement);
        let y_placement = take!(has_y_placement);
        let x_advance = take!(has_x_advance);
        let y_advance = take!(has_y_advance);
        let device_x_placement_offset = take!(has_device_x_placement);
        let device_y_placement_offset = take!(has_device_y_placement);
        let device_x_advance_offset = take!(has_device_x_advance);
        let device_y_advance_offset = take!(has_device_y_advance);
        macro_rules! take(
            ($offset:ident) => (match $offset {
                Some(offset) => Some(jump_take!(@unwrap tape, position, offset)),
                _ => None,
            });
        );
        let device_x_placement = take!(device_x_placement_offset);
        let device_y_placement = take!(device_y_placement_offset);
        let device_x_advance = take!(device_x_advance_offset);
        let device_y_advance = take!(device_y_advance_offset);
        Ok(Single {
            x_placement: x_placement,
            y_placement: y_placement,
            x_advance: x_advance,
            y_advance: y_advance,
            device_x_placement_offset: device_x_placement_offset,
            device_y_placement_offset: device_y_placement_offset,
            device_x_advance_offset: device_x_advance_offset,
            device_y_advance_offset: device_y_advance_offset,
            device_x_placement: device_x_placement,
            device_y_placement: device_y_placement,
            device_x_advance: device_x_advance,
            device_y_advance: device_y_advance,
        })
    }
}
<|endoftext|>


<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>>>>,

    code: Vec<Trigger>,

    is_running: bool,
}

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 {
    // Invariant: len() is the same as that of app.code
    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.
    // Invariant: outer len() is the same as that of self.requirements.
    // Invariant: inner len() is the same as number of input devices bound
    // to the corresponding requirement. May be empty.
    input_state: InputState,

    witnesses: Vec<Witness>,

    app: MonitorApp,
}

struct MonitorComm {
    tx: Sender<MonitorOp>,
    rx: Receiver<MonitorOp>,
}
struct MonitorTask {
    state: MonitorTaskState,
    comm: MonitorComm,
}

impl MonitorTask {
    fn new(app: MonitorApp) -> Self {
        // Initialize condition state.
        let mut trigger_condition_state = Vec::with_capacity(app.code.len());
        for _ in &app.code {
            trigger_condition_state.push(ConditionState {
                are_conditions_met: false,
            });
        }
        assert_eq!(trigger_condition_state.len(), app.code.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`.
            witnesses.push(
                watcher.add(
                    &state_index.get_individual_device(&app),
                    &state_index.get_input(&app),
                    &Range::any(),
                    |data| {
                        let _ = tx.send(MonitorOp::Update {
                            data: data,
                            index: state_index,
                        });
                        // Ignore errors. If the thread is shutting down, it's ok to lose messages.
                    }));
        }

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

    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.code, &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 _ = 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 {
    pub fn start(&mut self) {
        if self.is_running {
            return;
        }
        self.is_running = true;

        let mut task = MonitorTask::new(self.clone());
        thread::spawn(move || {
            task.run();
        });
    }
}

/// Data labelled with a user-readable name.
#[derive(Clone)]
struct Named<T> {
    /// 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>[fxbox/thinkerbell] Support for starting/stopping applications<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, 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>>
}

<|endoftext|>


<commit_before>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static A: u32 = 65;
static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
    buffer: Vec<char>               // Buffer to collect UTF-8 character bytes.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels,
            buffer: vec![]
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&self, card: Card) -> &Ante {
        println!("jump {}:{}", card.rank, card.suit);
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = std::char::from_u32(operands[0].suit).unwrap();

        if initial == A {
            initial = self.vars[target] as u32;
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = std::char::from_u32(operands[i].suit).unwrap();

            if rank == A {
                rank = self.vars[suit] as u32;
            }
            match suit {
                '♦' => initial += rank,
                '♥' => initial *= rank,
                '♠' => initial -= rank,
                '♣' => if rank != 0 {
                            initial /= rank;
                        } else {
                            self.exception("division by zero");
                        },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial as uint;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("hello.ante".as_slice()).run();
}
<commit_msg>"Hello, world!" works (dump)<commit_after>// Copyright (c) 2013-2104 Michael Dvorkin
// Ante is an esoteric programming language where all you've got is a deck of cards.
//
// This is Ante implementation in Rust.

extern crate regex;
extern crate num;

use std::io::File;
use std::collections::HashMap;

use regex::Regex;
use num::bigint::BigInt;

static A: u32 = 65;
static J: u32 = 74;
static Q: u32 = 81;
static K: u32 = 75;

struct Card {
    rank: u32,
    suit: u32
}

struct Ante {
    pc:     uint,                   // Program counter (index within ante.code)
    line:   uint,                   // Current line number.
    code:   Vec<Card>,              // Array of cards.
    vars:   HashMap<char, uint>,    // Four registers hashed by suit.
    labels: HashMap<uint, uint>,    // Labels for ante.pc to jump to.
}

impl Ante {
    fn new(filename: &str) -> Ante {
        let mut vars = HashMap::new();
        vars.insert('♦', 0);
        vars.insert('♥', 0);
        vars.insert('♠', 0);
        vars.insert('♣', 0);

        let code = Ante::parse(filename);
        let labels = Ante::resolve(&code);

        Ante {
            pc:     0,
            line:   0,
            code:   code,
            vars:   vars,
            labels: labels
        }
    }

    fn run(&mut self) -> &Ante {
        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            self.pc += 1;
            match card.rank {
                0  => self.newline(card),
                K  => self.jump(card),
                Q  => continue,
                J  => self.dump(card, true),
                10 => self.dump(card, false),
                _  => self.assign(card)
            };
        }
        self
    }

    // Turn source file into array of cards.
    fn parse(filename: &str) -> Vec<Card> {
        let mut file = File::open(&Path::new(filename));
        let program = file.read_to_string().unwrap();
        println!("file: {}", program);

        // Split program blob into lines getting rid of comments and whitespaces.
        let comments = Regex::new(r"#.*$").unwrap();
        let lines: Vec<String> = program.as_slice().lines().map( |line|
            comments.replace_all(line, "").as_slice().trim().to_string()
        ).collect();

        //\\ DEBUG //\\
        for i in range(0, lines.len()) {
            println!("{:2}) parsing: /{}/", i, lines[i]);
        }

        // Turn source file into array of cards. Each card a struct of rank and suit.
        let mut code: Vec<Card> = vec![];
        let card = Regex::new(r"(10|[2-9JQKA])([♦♥♠♣])").unwrap();
        for (i, line) in lines.iter().enumerate() {
            // Line number cards have zero rank.
            code.push(Card { rank: 0, suit: i as u32 + 1 });

            // Parse cards using regural expression. Card rank and suit characters get saved
            // as u32 runes (to cast u32 back to char use std::char::from_u32(ch).unwrap()).
            for caps in card.captures_iter(line.as_slice()) {
                let rank = caps.at(1).char_at(0);
                let suit = caps.at(2).char_at(0);
                let card = match rank {
                   '1'       => Card { rank: 10, suit: suit as u32 },
                   '2'...'9' => Card { rank: rank as u32 - 48, suit: suit as u32 },
                   _         => Card { rank: rank as u32, suit: suit as u32 }
                };
                code.push(card);
            }
        }

        //\\ DEBUG //\\
        for i in range(0, code.len()) {
            println!("{:2}) code: /{}:{}/", i, code[i].rank, code[i].suit);
        }
        code
    }

    // Extra pass to set up jump labels.
    fn resolve(code: &Vec<Card>) -> HashMap<uint, uint> {
        let mut pc = 0u;
        let mut labels: HashMap<uint, uint> = HashMap::new();

        while pc < code.len() - 1 {
            let card = code[pc];
            pc += 1;
            if card.rank == Q {
                let mut queen = card.suit as uint;
                while pc < code.len() && code[pc].rank == Q && code[pc].suit == card.suit {
                    queen += card.suit as uint;
                    pc += 1;
                }
                labels.insert(queen, pc);
            }
        }

        //\\ DEBUG //\\
        for (k,v) in labels.iter() {
            println!("label: /{} => {}/", k, v);
        }
        labels
    }

    fn newline(&mut self, card: Card) -> &Ante {
        //println!("newline {}:{}", card.rank, card.suit);
        self.line = card.suit as uint;
        self
    }

    fn jump(&self, card: Card) -> &Ante {
        //println!("jump {}:{}", card.rank, card.suit);
        self
    }

    fn assign(&mut self, card: Card) -> &Ante {
        //println!("assign {}:{}", card.rank, card.suit);
        let operands = self.remaining(card);
        self.expression(operands)
    }

    fn dump(&self, card: Card, as_character: bool) -> &Ante {
        //println!("dump {}:{} as character {}", card.rank, card.suit, as_character);
        let value = self.vars[std::char::from_u32(card.suit).unwrap()];
        if as_character {
            if value >= 0 as uint && value <= 255 as uint {
                print!("{}", std::char::from_u32(value as u32).unwrap());
            } else {
                self.exception(format!("character code {} is out of 0..255 range", value).as_slice());
            }
        } else {
            print!("{}", value);
        }
        self
    }

    fn remaining(&mut self, card: Card) -> Vec<Card> {
        let mut operands: Vec<Card> = vec![card];

        while self.pc < self.code.len() {
            let card = self.code[self.pc];
            if card.rank == 0 || card.rank == K || card.rank == Q || card.rank == J {
                break;
            }
            operands.push(card);
            self.pc += 1;
        }
        operands
    }

    fn expression(&mut self, operands: Vec<Card>) -> &Ante {
        let mut initial = operands[0].rank;
        let target = std::char::from_u32(operands[0].suit).unwrap();

        if initial == A {
            initial = self.vars[target] as u32;
        }

        for i in range(1, operands.len()) {
            let mut rank = operands[i].rank;
            let suit = std::char::from_u32(operands[i].suit).unwrap();

            if rank == A {
                rank = self.vars[suit] as u32;
            }
            match suit {
                '♦' => initial += rank,
                '♥' => initial *= rank,
                '♠' => initial -= rank,
                '♣' => if rank != 0 {
                            initial /= rank;
                        } else {
                            self.exception("division by zero");
                        },
                _ => continue
            }
        }

        *self.vars.get_mut(&target) = initial as uint;
        self
    }

    // NOTE: fail! got renamed to panic!
    fn exception(&self, message: &str) {
        fail!("Ante exception: {} on line {} (pc:{})\n", message, self.line, self.pc)
    }
}

fn main() {
    println!("usage: ante filename.ante");
    Ante::new("hello.ante".as_slice()).run();
}
<|endoftext|>


<commit_before>//! Implements some low-level analysis as a part of frontend

use frontend::radeco_containers::{CallContextInfo, CallGraph, RadecoFunction, RadecoModule};
use middle::ir::MOpcode;
use middle::ssa::ssa_traits::{NodeType, SSAWalk, SSA};
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use r2api::structs::FunctionInfo;

use std::collections::HashMap;
/// Converts call graph information from `Source`, represented in FunctionInfo,
/// into an actual graph with links.
pub fn load_call_graph(finfos: &[FunctionInfo], rmod: &RadecoModule) -> CallGraph {
    let mut cg = CallGraph::new();
    let node_map = finfos
        .iter()
        .map(|x| {
            let offset = x.offset.unwrap();
            (offset, cg.add_node(offset))
        })
        .collect::<HashMap<_, _>>();

    for x in finfos {
        let offset = x.offset.unwrap();
        let fnode = node_map.get(&offset);
        if let Some(ref callrefs) = x.callrefs {
            for cs in callrefs {
                match cs.call_type {
                    Some(ref c) if c != "C" => continue,
                    _ => {}
                }
                let mut cctx = CallContextInfo::default();
                cctx.csite = cs.source.expect("No source for call");
                let target = node_map.get(&cs.target.unwrap());
                match (fnode, target) {
                    (Some(cn), Some(tn)) => {
                        cg.add_edge(*cn, *tn, cctx);
                    }
                    (_, _) => {}
                }
            }
        }
    }

    // Initial callsite analysis to fix up CallContextInfo on the edges.
    for (offset, node) in &node_map {
        if let Some(rfn) = rmod.functions.get(offset) {
            let mut csites = analyze_callsite_initial(rfn);
            // Get callees of the node to update the cctx information that we just discovered
            let mut edges = cg.neighbors_directed(*node, Direction::Outgoing).detach();
            while let Some(call_edge) = edges.next_edge(&cg) {
                if let Some(cctx) = cg.edge_weight_mut(call_edge) {
                    if let Some(new_cctx) = csites.remove(&cctx.csite) {
                        *cctx = new_cctx;
                    }
                }
            }
        }
    }

    cg
}

/// Iterates through nodes in SSA for rfn and initializes the inital CallContextInfo
fn analyze_callsite_initial(rfn: &RadecoFunction) -> HashMap<u64, CallContextInfo> {
    let mut cctxs = HashMap::new();
    let ssa = rfn.ssa();
    for node in ssa.inorder_walk() {
        match ssa.node_data(node) {
            Ok(ref nd) => {
                if let NodeType::Op(MOpcode::OpCall) = nd.nt {
                    let offset = ssa.address(node).expect("").address;
                    let mut cctx = CallContextInfo::default();
                    let args_to_call = ssa.operands_of(node);
                    // Map operands/arguments to call in the caller context to invalid nodes in
                    // the callee context. These will be resolved later (hopefully)
                    // to be the argument nodes in the callee.
                    cctx.map = args_to_call
                        .iter()
                        .map(|&x| (x, NodeIndex::end()))
                        .collect();
                    // One mapping for the return value
                    cctx.map.push((node, NodeIndex::end()));
                    cctx.csite_node = node;
                    cctx.csite = offset;
                    cctxs.insert(offset, cctx);
                }
            }
            _ => {
                // Noop, we only analyze callsites
            }
        }
    }
    cctxs
}

pub fn init_call_ctx(rmod: &mut RadecoModule) {
    for wrapper in rmod.functions.iter() {
        let rfn = wrapper.1;
        let mut csites: HashMap<u64, CallContextInfo> = analyze_callsite_initial(rfn);
        // Iterate through callsites
        let mut cgwalker = rmod
            .callgraph
            .neighbors_directed(rfn.cgid(), Direction::Outgoing)
            .detach();
        for (csi, callee) in cgwalker.next(&rmod.callgraph) {
            let csite = rmod.callgraph[csi].csite;
            // Get args of callee
            let callee_off = rmod.callgraph[callee];

            let callee_info = if let Some(calleefn) = rmod.functions.get(&callee_off) {
                let mut args = calleefn
                    .bindings()
                    .into_iter()
                    .filter(|x| x.btype.is_argument() || x.btype.is_return())
                    .cloned()
                    .collect::<Vec<_>>();
                args.sort_by(|x, y| match (x.ridx, y.ridx) {
                    (Some(xidx), Some(ref yidx)) => xidx.cmp(yidx),
                    (_, _) => unreachable!(),
                });
                Some((calleefn.cgid(), args))
            } else if let Some(calleefn) = rmod.imports.get(&callee_off).map(|ifn| ifn.rfn.borrow())
            {
                let mut args = calleefn
                    .bindings()
                    .into_iter()
                    .filter(|x| x.btype.is_argument() || x.btype.is_return())
                    .cloned()
                    .collect::<Vec<_>>();
                args.sort_by(|x, y| match (x.ridx, y.ridx) {
                    (Some(xidx), Some(ref yidx)) => xidx.cmp(yidx),
                    (_, _) => unreachable!(),
                });
                Some((calleefn.cgid(), args))
            } else {
                None
            };

            if let Some((callee_cgid, args)) = callee_info {
                // Access the actual callsite in rfn.
                if let Some(mut cctx) = csites.remove(&csite) {
                    cctx.map = cctx
                        .map
                        .iter()
                        .map(|&(k, _)| k)
                        .zip(args.into_iter().map(|v| v.idx))
                        .collect();
                    // Update callsite information in the callgraph.
                    rmod.callgraph.update_edge(rfn.cgid(), callee_cgid, cctx);
                }
            }
        }
    }
}
<commit_msg>Fix the bug of callgraph construction<commit_after>//! Implements some low-level analysis as a part of frontend

use frontend::radeco_containers::{CallContextInfo, CallGraph, RadecoFunction, RadecoModule};
use middle::ir::MOpcode;
use middle::ssa::ssa_traits::{NodeType, SSAWalk, SSA};
use petgraph::graph::NodeIndex;
use petgraph::Direction;
use r2api::structs::FunctionInfo;

use std::collections::HashMap;
/// Converts call graph information from `Source`, represented in FunctionInfo,
/// into an actual graph with links.
pub fn load_call_graph(finfos: &[FunctionInfo], rmod: &RadecoModule) -> CallGraph {
    let mut cg = CallGraph::new();
    let node_map = finfos
        .iter()
        .map(|x| {
            let offset = x.offset.unwrap();
            (offset, cg.add_node(offset))
        })
        .collect::<HashMap<_, _>>();

    for x in finfos {
        let offset = x.offset.unwrap();
        let fnode = node_map.get(&offset);
        if let Some(ref callrefs) = x.callrefs {
            for cs in callrefs {
                match cs.call_type {
                    Some(ref c) if c != "CALL" => continue,
                    _ => {}
                }
                let mut cctx = CallContextInfo::default();
                cctx.csite = cs.source.expect("No source for call");
                let target = node_map.get(&cs.target.unwrap());
                match (fnode, target) {
                    (Some(cn), Some(tn)) => {
                        cg.add_edge(*cn, *tn, cctx);
                    }
                    (_, _) => {}
                }
            }
        }
    }

    // Initial callsite analysis to fix up CallContextInfo on the edges.
    for (offset, node) in &node_map {
        if let Some(rfn) = rmod.functions.get(offset) {
            let mut csites = analyze_callsite_initial(rfn);
            // Get callees of the node to update the cctx information that we just discovered
            let mut edges = cg.neighbors_directed(*node, Direction::Outgoing).detach();
            while let Some(call_edge) = edges.next_edge(&cg) {
                if let Some(cctx) = cg.edge_weight_mut(call_edge) {
                    if let Some(new_cctx) = csites.remove(&cctx.csite) {
                        *cctx = new_cctx;
                    }
                }
            }
        }
    }

    cg
}

/// Iterates through nodes in SSA for rfn and initializes the inital CallContextInfo
fn analyze_callsite_initial(rfn: &RadecoFunction) -> HashMap<u64, CallContextInfo> {
    let mut cctxs = HashMap::new();
    let ssa = rfn.ssa();
    for node in ssa.inorder_walk() {
        match ssa.node_data(node) {
            Ok(ref nd) => {
                if let NodeType::Op(MOpcode::OpCall) = nd.nt {
                    let offset = ssa.address(node).expect("").address;
                    let mut cctx = CallContextInfo::default();
                    let args_to_call = ssa.operands_of(node);
                    // Map operands/arguments to call in the caller context to invalid nodes in
                    // the callee context. These will be resolved later (hopefully)
                    // to be the argument nodes in the callee.
                    cctx.map = args_to_call
                        .iter()
                        .map(|&x| (x, NodeIndex::end()))
                        .collect();
                    // One mapping for the return value
                    cctx.map.push((node, NodeIndex::end()));
                    cctx.csite_node = node;
                    cctx.csite = offset;
                    cctxs.insert(offset, cctx);
                }
            }
            _ => {
                // Noop, we only analyze callsites
            }
        }
    }
    cctxs
}

pub fn init_call_ctx(rmod: &mut RadecoModule) {
    for wrapper in rmod.functions.iter() {
        let rfn = wrapper.1;
        let mut csites: HashMap<u64, CallContextInfo> = analyze_callsite_initial(rfn);
        // Iterate through callsites
        let mut cgwalker = rmod
            .callgraph
            .neighbors_directed(rfn.cgid(), Direction::Outgoing)
            .detach();
        for (csi, callee) in cgwalker.next(&rmod.callgraph) {
            let csite = rmod.callgraph[csi].csite;
            // Get args of callee
            let callee_off = rmod.callgraph[callee];

            let callee_info = if let Some(calleefn) = rmod.functions.get(&callee_off) {
                let mut args = calleefn
                    .bindings()
                    .into_iter()
                    .filter(|x| x.btype.is_argument() || x.btype.is_return())
                    .cloned()
                    .collect::<Vec<_>>();
                args.sort_by(|x, y| match (x.ridx, y.ridx) {
                    (Some(xidx), Some(ref yidx)) => xidx.cmp(yidx),
                    (_, _) => unreachable!(),
                });
                Some((calleefn.cgid(), args))
            } else if let Some(calleefn) = rmod.imports.get(&callee_off).map(|ifn| ifn.rfn.borrow())
            {
                let mut args = calleefn
                    .bindings()
                    .into_iter()
                    .filter(|x| x.btype.is_argument() || x.btype.is_return())
                    .cloned()
                    .collect::<Vec<_>>();
                args.sort_by(|x, y| match (x.ridx, y.ridx) {
                    (Some(xidx), Some(ref yidx)) => xidx.cmp(yidx),
                    (_, _) => unreachable!(),
                });
                Some((calleefn.cgid(), args))
            } else {
                None
            };

            if let Some((callee_cgid, args)) = callee_info {
                // Access the actual callsite in rfn.
                if let Some(mut cctx) = csites.remove(&csite) {
                    cctx.map = cctx
                        .map
                        .iter()
                        .map(|&(k, _)| k)
                        .zip(args.into_iter().map(|v| v.idx))
                        .collect();
                    // Update callsite information in the callgraph.
                    rmod.callgraph.update_edge(rfn.cgid(), callee_cgid, cctx);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::time::Duration;

use serde::{Deserialize, Serialize};

use crate::components::*;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ServerMessage {
    /// Server time since session start.
    pub session_time: Duration,
    /// List of new entities.
    pub new_entities: Vec<Vec<Component>>,
    /// List of updated components.
    pub changed_components: Vec<(GameEntityId, Component)>,
}

impl ServerMessage {
    pub fn new(session_time: Duration) -> ServerMessage {
        ServerMessage {
            session_time,
            new_entities: Vec::new(),
            changed_components: Vec::new(),
        }
    }
}
<commit_msg>Document ServerMessage<commit_after>use std::time::Duration;

use serde::{Deserialize, Serialize};

use crate::components::*;

/// A message sent from the server to a client.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ServerMessage {
    /// Server time since session start.
    pub session_time: Duration,
    /// List of new entities.
    pub new_entities: Vec<Vec<Component>>,
    /// List of updated components.
    pub changed_components: Vec<(GameEntityId, Component)>,
}

impl ServerMessage {
    pub fn new(session_time: Duration) -> ServerMessage {
        ServerMessage {
            session_time,
            new_entities: Vec::new(),
            changed_components: Vec::new(),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use fmt;
use future::Future;
use marker::{PhantomData, Unpin};
use mem::PinMut;
use task::{Context, Poll};

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Future<Output = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Future` trait is currently not object safe: The `Future::poll`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct LocalFutureObj<'a, T> {
    ptr: *mut (),
    poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> LocalFutureObj<'a, T> {
    /// Create a `LocalFutureObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
        LocalFutureObj {
            ptr: f.into_raw(),
            poll_fn: F::poll,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalFutureObj` into a `FutureObj`
    /// To make this operation safe one has to ensure that the `UnsafeFutureObj`
    /// instance from which this `LocalFutureObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> {
        FutureObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalFutureObj")
            .finish()
    }
}

impl<'a, T> From<FutureObj<'a, T>> for LocalFutureObj<'a, T> {
    #[inline]
    fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> {
        f.0
    }
}

impl<'a, T> Future for LocalFutureObj<'a, T> {
    type Output = T;

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
        unsafe {
            (self.poll_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalFutureObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Future<Output = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Future` trait is currently not object safe: The `Future::poll`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>);

unsafe impl<'a, T> Send for FutureObj<'a, T> {}

impl<'a, T> FutureObj<'a, T> {
    /// Create a `FutureObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeFutureObj<'a, T> + Send>(f: F) -> FutureObj<'a, T> {
        FutureObj(LocalFutureObj::new(f))
    }
}

impl<'a, T> fmt::Debug for FutureObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("FutureObj")
            .finish()
    }
}

impl<'a, T> Future for FutureObj<'a, T> {
    type Output = T;

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll(cx)
    }
}

/// A custom implementation of a future trait object for `FutureObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F
    where F: Future<Output = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}
<commit_msg>Implement Unpin for FutureObj and LocalFutureObj<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use fmt;
use future::Future;
use marker::{PhantomData, Unpin};
use mem::PinMut;
use task::{Context, Poll};

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Future<Output = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Future` trait is currently not object safe: The `Future::poll`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct LocalFutureObj<'a, T> {
    ptr: *mut (),
    poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<T>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalFutureObj<'a, T> {}

impl<'a, T> LocalFutureObj<'a, T> {
    /// Create a `LocalFutureObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeFutureObj<'a, T> + 'a>(f: F) -> LocalFutureObj<'a, T> {
        LocalFutureObj {
            ptr: f.into_raw(),
            poll_fn: F::poll,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalFutureObj` into a `FutureObj`
    /// To make this operation safe one has to ensure that the `UnsafeFutureObj`
    /// instance from which this `LocalFutureObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> {
        FutureObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalFutureObj")
            .finish()
    }
}

impl<'a, T> From<FutureObj<'a, T>> for LocalFutureObj<'a, T> {
    #[inline]
    fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> {
        f.0
    }
}

impl<'a, T> Future for LocalFutureObj<'a, T> {
    type Output = T;

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
        unsafe {
            (self.poll_fn)(self.ptr, cx)
        }
    }
}

impl<'a, T> Drop for LocalFutureObj<'a, T> {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling futures, roughly akin to
/// `Box<dyn Future<Output = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Future` trait is currently not object safe: The `Future::poll`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>);

impl<'a, T> Unpin for FutureObj<'a, T> {}
unsafe impl<'a, T> Send for FutureObj<'a, T> {}

impl<'a, T> FutureObj<'a, T> {
    /// Create a `FutureObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeFutureObj<'a, T> + Send>(f: F) -> FutureObj<'a, T> {
        FutureObj(LocalFutureObj::new(f))
    }
}

impl<'a, T> fmt::Debug for FutureObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("FutureObj")
            .finish()
    }
}

impl<'a, T> Future for FutureObj<'a, T> {
    type Output = T;

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll(cx)
    }
}

/// A custom implementation of a future trait object for `FutureObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeFutureObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T>;

    /// Drops the future represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F
    where F: Future<Output = T> + Unpin + 'a
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
        PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}
<|endoftext|>