<commit_before>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// The public API.
pub trait API {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/node/list`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_node_tag(set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/service/list`
    fn get_input_services(&Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/service/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/service/value`
    fn get_service_value(&Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/service/value`
    fn put_service_value(&Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/service/watch`
    fn register_service_watch<F>(WatchOptions, cb: F) -> Self::WatchGuard
        where F: FnMut(WatchEvent) + Send + Sync;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    source: InputRequest,

    /// If `true`, watch as new values become available.
    should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    should_watch_topology: bool,
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<commit_msg>[fxbox/taxonomy] register_service_watch now accepts a vector<commit_after>//!
//! The API for communicating with devices.
//!
//! This API is provided as Traits to be implemented:
//!
//! - by the low-level layers of the FoxBox, including the adapters;
//! - by test suites and tools that need to simulate connected devices.
//!
//! In turn, this API is used to implement:
//!
//! - the public-facing REST and WebSocket API;
//! - the rules API (ThinkerBell).
//!
//!

use devices::*;
use requests::*;
use values::Value;

/// An error produced by one of the APIs in this module.
pub enum Error {
    /// There is no such node connected to the Foxbox, even indirectly.
    NoSuchNode(NodeId),

    /// There is no such service connected to the Foxbox, even indirectly.
    NoSuchService(ServiceId),

    /// Attempting to set a value with the wrong type
    TypeError,
}

/// An event during watching.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum WatchEvent {
    /// A new value is available.
    Value {
        /// The service that sent the value.
        from: ServiceId,

        /// The actual value.
        value: Value
    },

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// removed. Payload is the id of the device that was removed.
    InputRemoved(ServiceId),

    /// The set of devices being watched has changed, typically either
    /// because a tag was edited or because a device was
    /// added. Payload is the id of the device that was added.
    InputAdded(ServiceId),
}

/// The public API.
pub trait API {
    /// Get the metadata on nodes matching some conditions.
    ///
    /// A call to `API::get_nodes(vec![req1, req2, ...])` will return
    /// the metadata on all nodes matching _either_ `req1` or `req2`
    /// or ...
    ///
    /// # REST API
    ///
    /// `GET /api/v1/node/list`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to a `Vec<NodeRequest>`. See
    /// the implementation of `NodeRequest` for details.
    ///
    /// ### Example
    ///
    /// Request all doors in the entrance (tags `door`, `entrance`)
    /// that support output service `OpenClose`
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door"],
    ///   "inputs": [
    ///     {
    ///       "kind": {
    ///         "Exactly": {
    ///           "OpenClose": []
    ///         }
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    ///
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing an array of `Node`. See the implementation
    /// of `Node` for details.
    ///
    /// ### Example
    ///
    /// ```json
    /// [{
    ///   "tags": ["entrance", "door", "somevendor"],
    ///   "id: "some-node-id",
    ///   "inputs": [],
    ///   "outputs": [
    ///     "tags": [...],
    ///     "id": "some-service-id",
    ///     "node": "some-node-id",
    ///     "last_seen": "some-date",
    ///     "mechanism": {
    ///       "Output":  {
    ///         "kind": {
    ///           "OnOff": []
    ///         },
    ///         "push": [5000],
    ///         "updated": "some-date",
    ///       }
    ///     }
    ///   ]
    /// }]
    /// ```
    fn get_nodes(&Vec<NodeRequest>) -> Vec<Node>;

    /// Label a set of nodes with a set of tags.
    ///
    /// A call to `API::put_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the nodes matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_node_tag(set: &Vec<NodeRequest>, tags: &Vec<String>) -> usize;

    /// Remove a set of tags from a set of nodes.
    ///
    /// A call to `API::delete_node_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the nodes matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of nodes
    /// matching any of the requests.
    ///
    /// Some of the nodes may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if nodes
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<NodeRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_node_tag(set: &Vec<NodeRequest>, tags: String) -> usize;

    /// Get a list of inputs matching some conditions
    ///
    /// # REST API
    ///
    /// `GET /api/v1/service/list`
    fn get_input_services(&Vec<InputRequest>) -> Vec<Service<Input>>;
    fn get_output_services(&Vec<OutputRequest>) -> Vec<Service<Output>>;

    /// Label a set of services with a set of tags.
    ///
    /// A call to `API::put_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will label all the services matching _either_ `req1` or
    /// `req2` or ... with `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may already be labelled with `tag1`, or
    /// `tag2`, ... They will not change state. They are counted in
    /// the resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/service/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn put_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn put_output_tag(&Vec<OutputRequest>, &Vec<String>) -> usize;

    /// Remove a set of tags from a set of services.
    ///
    /// A call to `API::delete_{input, output}_tag(vec![req1, req2, ...], vec![tag1,
    /// ...])` will remove from all the services matching _either_ `req1` or
    /// `req2` or ... all of the tags `tag1`, ... and return the number of services
    /// matching any of the requests.
    ///
    /// Some of the services may not be labelled with `tag1`, or `tag2`,
    /// ... They will not change state. They are counted in the
    /// resulting `usize` nevertheless.
    ///
    /// Note that this call is _not live_. In other words, if services
    /// are added after the call, they will not be affected.
    ///
    /// # REST API
    ///
    /// `DELETE /api/v1/node/tag`
    ///
    /// ## Inputs
    ///
    /// Any JSON that can be deserialized to
    ///
    /// ```rust
    /// {
    ///   set: Vec<InputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    /// or
    /// ```rust
    /// {
    ///   set: Vec<OutputRequest>,
    ///   tags: Vec<String>,
    /// }
    /// ```
    ///
    /// ## Errors
    ///
    /// In case of syntax error, Error 400, accompanied with a
    /// somewhat human-readable JSON string detailing the error.
    ///
    /// ## Success
    ///
    /// A JSON representing a number.
    fn delete_input_tag(&Vec<InputRequest>, &Vec<String>) -> usize;
    fn delete_output_tag(&Vec<InputRequest>, &Vec<String>) -> usize;

    /// Read the latest value from a set of services
    ///
    /// # REST API
    ///
    /// `GET /api/v1/service/value`
    fn get_service_value(&Vec<InputRequest>) -> Vec<(ServiceId, Result<Value, Error>)>;

    /// Send one value to a set of services
    ///
    /// # REST API
    ///
    /// `PUT /api/v1/service/value`
    fn put_service_value(&Vec<OutputRequest>, Value) -> Vec<(ServiceId, Result<(), Error>)>;

    /// Watch for any change
    ///
    /// # WebSocket API
    ///
    /// `/api/v1/service/watch`
    fn register_service_watch<F>(Vec<WatchOptions>, cb: F) -> Self::WatchGuard
        where F: FnMut(WatchEvent) + Send + Sync;

    /// A value that causes a disconnection once it is dropped.
    type WatchGuard;
}

/// Options for watching changes in one or more services.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct WatchOptions {
    /// The set of inputs to watch. Note that the actual inputs in the
    /// set may change over time.
    source: InputRequest,

    /// If `true`, watch as new values become available.
    should_watch_values: bool,

    /// If `true`, watch as nodes are connected/disconnected.
    should_watch_topology: bool,
}

impl WatchOptions {
    pub fn new() -> Self {
        WatchOptions {
            source: InputRequest::new(),
            should_watch_values: false,
            should_watch_topology: false,
        }
    }

    /// Restrict to input services in a given set.
    ///
    /// Also note that the actual input services that are part of the
    /// set may change with time, for instance if devices are added
    /// ore removed.  The request _is live_, i.e. the service watch
    /// will continue watching any input services that match `req`.
    pub fn with_inputs(self, req: InputRequest) -> Self {
        WatchOptions {
            source: self.source.and(req),
            ..self
        }
    }

    pub fn with_watch_values(self, should: bool) -> Self {
        WatchOptions {
            should_watch_values: should,
            ..self
        }
    }

    pub fn with_watch_topology(self, should: bool) -> Self {
        WatchOptions {
            should_watch_topology: should,
            ..self
        }
    }
}
<|endoftext|>


<commit_before>//use Tensor;
//use tensor;

/// Macro for creating vectors and matrices.
///
/// To use this macro, import Numeric as follows:
///
/// ```text
/// #[macro_use(tensor)]
/// extern crate numeric;
/// ```
///
/// # Examples
///
/// 1D tensor (vector):
///
/// ```
/// # #[macro_use] extern crate numeric; fn main() {
/// let x = tensor![1.0, 2.0, 3.0];
/// # assert!(x == numeric::Tensor::new(vec![1.0, 2.0, 3.0]));
/// # }
/// ```
///
/// 2D tensor (matrix):
///
/// ```
/// # #[macro_use] extern crate numeric; use numeric::tensor; fn main() {
/// let x = tensor![1, 0; 3, 2; 5, 4];
/// # assert!(x == numeric::Tensor::new(vec![1, 0, 3, 2, 5, 4]).reshape(&[3, 2]));
/// # }
/// ```
///
/// 1D tensor filled with a single value:
///
/// ```
/// # #[macro_use] extern crate numeric; use numeric::tensor; fn main() {
/// let x = tensor![2.0; 5];
/// # assert!(x == numeric::Tensor::new(vec![2.0, 2.0, 2.0, 2.0, 2.0]));
/// # }
/// ```
#[macro_export]
macro_rules! tensor {
    (@count) => (0);
    (@count $head:tt $($tail:tt)*) => (1 + tensor!(@count $($tail)*));
    ($elem:expr; $n:expr) => (
        $crate::Tensor::new(vec![$elem; $n])
    );
    ($($x:expr),*) => (
        $crate::Tensor::new(vec![$($x),*])
    );
    ($($x:expr,)*) => (
        tensor![$($x),*]
    );
    ($($($x:expr),*;)*) => (
        $crate::Tensor::new(vec![$($($x),*),*]).reshape(&[tensor!(@count $([$($x),*])*), -1])
    );
    ($($($x:expr),*);*) => (
        tensor![$($($x),*;)*]
    );
}
<commit_msg>DOC: Removed old comments<commit_after>/// Macro for creating vectors and matrices.
///
/// To use this macro, import Numeric as follows:
///
/// ```text
/// #[macro_use(tensor)]
/// extern crate numeric;
/// ```
///
/// # Examples
///
/// 1D tensor (vector):
///
/// ```
/// # #[macro_use] extern crate numeric; fn main() {
/// let x = tensor![1.0, 2.0, 3.0];
/// # assert!(x == numeric::Tensor::new(vec![1.0, 2.0, 3.0]));
/// # }
/// ```
///
/// 2D tensor (matrix):
///
/// ```
/// # #[macro_use] extern crate numeric; use numeric::tensor; fn main() {
/// let x = tensor![1, 0; 3, 2; 5, 4];
/// # assert!(x == numeric::Tensor::new(vec![1, 0, 3, 2, 5, 4]).reshape(&[3, 2]));
/// # }
/// ```
///
/// 1D tensor filled with a single value:
///
/// ```
/// # #[macro_use] extern crate numeric; use numeric::tensor; fn main() {
/// let x = tensor![2.0; 5];
/// # assert!(x == numeric::Tensor::new(vec![2.0, 2.0, 2.0, 2.0, 2.0]));
/// # }
/// ```
#[macro_export]
macro_rules! tensor {
    (@count) => (0);
    (@count $head:tt $($tail:tt)*) => (1 + tensor!(@count $($tail)*));
    ($elem:expr; $n:expr) => (
        $crate::Tensor::new(vec![$elem; $n])
    );
    ($($x:expr),*) => (
        $crate::Tensor::new(vec![$($x),*])
    );
    ($($x:expr,)*) => (
        tensor![$($x),*]
    );
    ($($($x:expr),*;)*) => (
        $crate::Tensor::new(vec![$($($x),*),*]).reshape(&[tensor!(@count $([$($x),*])*), -1])
    );
    ($($($x:expr),*);*) => (
        tensor![$($($x),*;)*]
    );
}
<|endoftext|>


<commit_before>use llvm_sys::prelude::LLVMValueRef;

use std::fmt::Debug;

use values::{ArrayValue, AggregateValueEnum, StructValue, BasicValueEnum, AnyValueEnum, IntValue, FloatValue, PointerValue, PhiValue, VectorValue, FunctionValue, InstructionValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsValueRef {
    fn as_value_ref(&self) -> LLVMValueRef;
}

macro_rules! trait_value_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl $trait_name for $args {}
        )*

        // REVIEW: Possible encompassing methods to implement:
        // as_instruction, is_sized, ge/set metadata methods
    );
}

/// Represents an aggregate value, built on top of other values.
pub trait AggregateValue: AnyValue {
    /// Returns an enum containing a typed version of the `AggregateValue`.
    fn as_aggregate_value_enum(&self) -> AggregateValueEnum {
        AggregateValueEnum::new(self.as_value_ref())
    }
}

/// Represents a basic value, which can be used both by itself, or in an `AggregateValue`.
pub trait BasicValue: AnyValue {
    /// Returns an enum containing a typed version of the `BasicValue`.
    fn as_basic_value_enum(&self) -> BasicValueEnum {
        BasicValueEnum::new(self.as_value_ref())
    }
}

/// Defines any struct wrapping an LLVM value.
pub trait AnyValue: AsValueRef + Debug {
    /// Returns an enum containing a typed version of `AnyValue`.
    fn as_any_value_enum(&self) -> AnyValueEnum {
        AnyValueEnum::new(self.as_value_ref())
    }
}

trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, InstructionValue}
trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, StructValue, PointerValue, VectorValue}
<commit_msg>Made AggregateValue implement BasicValue instead of AnyValue.<commit_after>use llvm_sys::prelude::LLVMValueRef;

use std::fmt::Debug;

use values::{ArrayValue, AggregateValueEnum, StructValue, BasicValueEnum, AnyValueEnum, IntValue, FloatValue, PointerValue, PhiValue, VectorValue, FunctionValue, InstructionValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsValueRef {
    fn as_value_ref(&self) -> LLVMValueRef;
}

macro_rules! trait_value_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl $trait_name for $args {}
        )*

        // REVIEW: Possible encompassing methods to implement:
        // as_instruction, is_sized, ge/set metadata methods
    );
}

/// Represents an aggregate value, built on top of other values.
pub trait AggregateValue: BasicValue {
    /// Returns an enum containing a typed version of the `AggregateValue`.
    fn as_aggregate_value_enum(&self) -> AggregateValueEnum {
        AggregateValueEnum::new(self.as_value_ref())
    }
}

/// Represents a basic value, which can be used both by itself, or in an `AggregateValue`.
pub trait BasicValue: AnyValue {
    /// Returns an enum containing a typed version of the `BasicValue`.
    fn as_basic_value_enum(&self) -> BasicValueEnum {
        BasicValueEnum::new(self.as_value_ref())
    }
}

/// Defines any struct wrapping an LLVM value.
pub trait AnyValue: AsValueRef + Debug {
    /// Returns an enum containing a typed version of `AnyValue`.
    fn as_any_value_enum(&self) -> AnyValueEnum {
        AnyValueEnum::new(self.as_value_ref())
    }
}

trait_value_set! {AggregateValue: ArrayValue, AggregateValueEnum, StructValue}
trait_value_set! {AnyValue: AnyValueEnum, BasicValueEnum, AggregateValueEnum, ArrayValue, IntValue, FloatValue, PhiValue, PointerValue, FunctionValue, StructValue, VectorValue, InstructionValue}
trait_value_set! {BasicValue: ArrayValue, BasicValueEnum, AggregateValueEnum, IntValue, FloatValue, StructValue, PointerValue, VectorValue}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use super::Context;
use super::{VertexData, VertexBytes, VertexAttribBinder};
use super::Buffer;
use super::{BufferBinding, ArrayBufferBinding};

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    pub buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn new(buffer: Buffer) -> Self {
        VertexBuffer {
            attrib_binder: None,
            buffer: buffer,
            count: 0,
            phantom: PhantomData
        }
    }
}
<commit_msg>Add `VertexBuffer.build_attrib_binder()`<commit_after>use std::marker::PhantomData;
use super::Context;
use super::{VertexData, VertexBytes, VertexAttribBinder};
use super::Buffer;
use super::{BufferBinding, ArrayBufferBinding};

pub struct VertexBuffer<T: VertexData> {
    pub attrib_binder: Option<T::Binder>,
    pub buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn new(buffer: Buffer) -> Self {
        VertexBuffer {
            attrib_binder: None,
            buffer: buffer,
            count: 0,
            phantom: PhantomData
        }
    }

    pub fn build_attrib_binder(&self)
        -> <T::Binder as VertexAttribBinder>::Builder
    {
        T::build_attrib_binder()
    }
}
<|endoftext|>


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

use std::fmt;
use std::str::FromStr;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base::ItemDecorator;

/// A component modifier.
#[derive(Copy, PartialEq)]
enum Modifier {
    /// Corresponds to the `#[normalized]` attribute.
    ///
    /// Normalizes the component at runtime. Unsigned integers are normalized to
    /// `[0, 1]`. Signed integers are normalized to `[-1, 1]`.
    Normalized,
    /// Corresponds to the `#[as_float]` attribute.
    ///
    /// Casts the component to a float precision floating-point number at runtime.
    AsFloat,
    /// Corresponds to the `#[as_double]` attribute.
    ///
    /// Specifies a high-precision float.
    AsDouble,
}

impl fmt::Debug for Modifier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Modifier::Normalized => write!(f, "normalized"),
            Modifier::AsFloat => write!(f, "as_float"),
            Modifier::AsDouble => write!(f, "as_double"),
        }
    }
}

impl FromStr for Modifier {
    type Err = ();

    fn from_str(src: &str) -> Result<Modifier, ()> {
        match src {
            "normalized" => Ok(Modifier::Normalized),
            "as_float" => Ok(Modifier::AsFloat),
            "as_double" => Ok(Modifier::AsDouble),
            _ => Err(()),
        }
    }
}

/// Scan through the field's attributes and extract a relevant modifier. If
/// multiple modifier attributes are found, use the first modifier and emit a
/// warning.
fn find_modifier(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 attributes: &[ast::Attribute]) -> Option<Modifier> {
    attributes.iter().fold(None, |modifier, attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) => {
                word.parse().ok().and_then(|new_modifier| {
                    attr::mark_used(attribute);
                    modifier.map_or(Some(new_modifier), |modifier| {
                        cx.span_warn(span, &format!(
                            "Extra attribute modifier detected: `#[{:?}]` - \
                            ignoring in favour of `#[{:?}]`.", new_modifier, modifier
                        ));
                        None
                    })
                }).or(modifier)
            },
            _ => modifier,
        }
    })
}

/// Find a `gfx::attrib::Type` that describes the given type identifier.
fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               ty_ident: &ast::Ident, modifier: Option<Modifier>,
               path_root: ast::Ident) -> P<ast::Expr> {
    let ty_str = ty_ident.name.as_str();
    match ty_str {
        "f32" | "f64" => {
            let kind = cx.ident_of(match modifier {
                None | Some(Modifier::AsFloat) => "Default",
                Some(Modifier::AsDouble) => "Precision",
                Some(Modifier::Normalized) => {
                    cx.span_warn(span, &format!(
                        "Incompatible float modifier attribute: `#[{:?}]`", modifier
                    ));
                    ""
                }
            });
            let size = cx.ident_of(&format!("F{}", &ty_str[1..]));
            quote_expr!(cx, $path_root::gfx::attrib::Type::Float($path_root::gfx::attrib::FloatSubType::$kind,
                                                                 $path_root::gfx::attrib::FloatSize::$size))
        },
        "u8" | "u16" | "u32" | "u64" |
        "i8" | "i16" | "i32" | "i64" => {
            let sign = cx.ident_of({
                if ty_str.starts_with("i") { "Signed" } else { "Unsigned" }
            });
            let kind = cx.ident_of(match modifier {
                None => "Raw",
                Some(Modifier::Normalized) => "Normalized",
                Some(Modifier::AsFloat) => "AsFloat",
                Some(Modifier::AsDouble) => {
                    cx.span_warn(span, &format!(
                        "Incompatible int modifier attribute: `#[{:?}]`", modifier
                    ));
                    ""
                }
            });
            let size = cx.ident_of(&format!("U{}", &ty_str[1..]));
            quote_expr!(cx, $path_root::gfx::attrib::Type::Int($path_root::gfx::attrib::IntSubType::$kind,
                                                               $path_root::gfx::attrib::IntSize::$size,
                                                               $path_root::gfx::attrib::SignFlag::$sign))
        },
        ty_str => {
            cx.span_err(span, &format!("Unrecognized component type: `{:?}`",
                                      ty_str));
            cx.expr_tuple(span, vec![])
        },
    }
}

fn decode_count_and_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                         field: &ast::StructField,
                         path_root: ast::Ident) -> (P<ast::Expr>, P<ast::Expr>) {
    let modifier = find_modifier(cx, span, &field.node.attrs);
    match field.node.ty.node {
        ast::TyPath(_,ref p) => (
            cx.expr_lit(span, ast::LitInt(1, ast::UnsuffixedIntLit(ast::Plus))),
            decode_type(cx, span, &p.segments[0].identifier, modifier, path_root),
        ),
        ast::TyFixedLengthVec(ref pty, ref expr) => (expr.clone(), match pty.node {
            ast::TyPath(_,ref p) => {
                decode_type(cx, span, &p.segments[0].identifier, modifier, path_root)
            },
            _ => {
                cx.span_err(span, &format!("Unsupported fixed vector sub-type: \
                                          `{:?}`",pty.node));
                cx.expr_tuple(span, vec![])
            },
        }),
        _ => {
            cx.span_err(span, &format!("Unsupported attribute type: `{:?}`",
                                      field.node.ty.node));
            (cx.expr_tuple(span, vec![]), cx.expr_tuple(span, vec![]))
        },
    }
}

/// Generates the the method body for `gfx::VertexFormat::generate`.
fn method_body(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure,
                   path_root: ast::Ident) -> P<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let attribute_pushes = definition.fields.iter().zip(fields.iter())
                .map(|(def, &(ident, _))| {
                    let struct_ident = substr.type_ident;
                    let buffer_expr = &substr.nonself_args[1];
                    let (count_expr, type_expr) = decode_count_and_type(cx, span, def, path_root);
                    let ident_str = match super::find_name(cx, span, &def.node.attrs) {
                        Some(name) => name,
                        None => token::get_ident(ident),
                    };
                    let ident_str = &ident_str[..];
                    let instance_expr = cx.expr_u8(span, 0); // not supposed to be set by the macro
                    quote_expr!(cx, {
                        attributes.push($path_root::gfx::Attribute {
                            name: $ident_str.to_string(),
                            buffer: $buffer_expr.clone(),
                            format: $path_root::gfx::attrib::Format {
                                elem_count: $count_expr,
                                elem_type: $type_expr,
                                offset: unsafe {
                                    let x: $struct_ident = ::std::mem::uninitialized();
                                    let offset = (&x.$ident as *const _ as usize) -
                                        (&x as *const _ as usize);
                                    ::std::mem::forget(x);
                                    offset as $path_root::gfx::attrib::Offset
                                },
                                stride: { use std::mem;
                                    mem::size_of::<$struct_ident>() as
                                        $path_root::gfx::attrib::Stride
                                },
                                instance_rate: $instance_expr,
                            }
                        });
                    })
                }).collect::<Vec<P<ast::Expr>>>();
            let capacity = fields.len();
            quote_expr!(cx, {
                let mut attributes = Vec::with_capacity($capacity);
                $attribute_pushes;
                attributes
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `gfx::VertexFormat::generate` \
                              on a non-structure");
            cx.expr_tuple(span, vec![])
        }
    }
}

#[derive(Copy)]
pub struct VertexFormat;

impl ItemDecorator for VertexFormat {
    /// Derive a `gfx::VertexFormat` implementation for the `struct`
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>)) {
        // Insert the `gfx` reexport module
        let path_root = super::extern_crate_hack(context, span, |i| (*push)(i));
        let fixup = |item| {
            (*push)(super::fixup_extern_crate_paths(item, path_root))
        };

        // `impl<R: gfx::Resources> gfx::VertexFormat for $item`
        generic::TraitDef {
            span: span,
            attributes: Vec::new(),
            path: generic::ty::Path::new(
                vec![super::EXTERN_CRATE_HACK, "gfx", "VertexFormat"],
            ),
            additional_bounds: Vec::new(),
            generics: generic::ty::LifetimeBounds::empty(),
            methods: vec![
                // `fn generate(Option<Self>, gfx::RawBufferHandle) -> Vec<gfx::Attribute>`
                generic::MethodDef {
                    name: "generate",
                    generics: generic::ty::LifetimeBounds {
                        lifetimes: Vec::new(),
                        bounds: vec![
                            ("R", vec![
                                generic::ty::Path::new(vec![
                                    super::EXTERN_CRATE_HACK, "gfx", "Resources"
                                ]),
                            ]),
                        ],
                    },
                    explicit_self: None,
                    args: vec![
                        generic::ty::Literal(generic::ty::Path {
                            path: vec!["Option"],
                            lifetime: None,
                            params: vec![box generic::ty::Ptr(
                                box generic::ty::Self_,
                                generic::ty::PtrTy::Borrowed(None, ast::Mutability::MutImmutable)
                            )],
                            global: false,
                        }),
                        generic::ty::Literal(generic::ty::Path {
                            path: vec![super::EXTERN_CRATE_HACK, "gfx", "RawBufferHandle"],
                            lifetime: None,
                            params: vec![box generic::ty::Literal(generic::ty::Path::new_local("R"))],
                            global: false,
                        }),
                    ],
                    ret_ty: generic::ty::Literal(
                        generic::ty::Path {
                            path: vec!["Vec"],
                            lifetime: None,
                            params: vec![
                                box generic::ty::Literal(generic::ty::Path {
                                    path: vec![super::EXTERN_CRATE_HACK, "gfx", "Attribute"],
                                    lifetime: None,
                                    params: vec![box generic::ty::Literal(
                                        generic::ty::Path::new_local("R")
                                    )],
                                    global: false,
                                }),
                            ],
                            global: false,
                        },
                    ),
                    attributes: Vec::new(),
                    // generate the method body
                    combine_substructure: generic::combine_substructure(
                        box |c, s, ss| method_body(c, s, ss, path_root)),
                },
            ],
            associated_types: Vec::new(),
        }.expand(context, meta_item, item, fixup);
    }
}
<commit_msg>Remove unused arg from VertexFormat::generate<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::str::FromStr;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::{attr, codemap};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base::ItemDecorator;

/// A component modifier.
#[derive(Copy, PartialEq)]
enum Modifier {
    /// Corresponds to the `#[normalized]` attribute.
    ///
    /// Normalizes the component at runtime. Unsigned integers are normalized to
    /// `[0, 1]`. Signed integers are normalized to `[-1, 1]`.
    Normalized,
    /// Corresponds to the `#[as_float]` attribute.
    ///
    /// Casts the component to a float precision floating-point number at runtime.
    AsFloat,
    /// Corresponds to the `#[as_double]` attribute.
    ///
    /// Specifies a high-precision float.
    AsDouble,
}

impl fmt::Debug for Modifier {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Modifier::Normalized => write!(f, "normalized"),
            Modifier::AsFloat => write!(f, "as_float"),
            Modifier::AsDouble => write!(f, "as_double"),
        }
    }
}

impl FromStr for Modifier {
    type Err = ();

    fn from_str(src: &str) -> Result<Modifier, ()> {
        match src {
            "normalized" => Ok(Modifier::Normalized),
            "as_float" => Ok(Modifier::AsFloat),
            "as_double" => Ok(Modifier::AsDouble),
            _ => Err(()),
        }
    }
}

/// Scan through the field's attributes and extract a relevant modifier. If
/// multiple modifier attributes are found, use the first modifier and emit a
/// warning.
fn find_modifier(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                 attributes: &[ast::Attribute]) -> Option<Modifier> {
    attributes.iter().fold(None, |modifier, attribute| {
        match attribute.node.value.node {
            ast::MetaWord(ref word) => {
                word.parse().ok().and_then(|new_modifier| {
                    attr::mark_used(attribute);
                    modifier.map_or(Some(new_modifier), |modifier| {
                        cx.span_warn(span, &format!(
                            "Extra attribute modifier detected: `#[{:?}]` - \
                            ignoring in favour of `#[{:?}]`.", new_modifier, modifier
                        ));
                        None
                    })
                }).or(modifier)
            },
            _ => modifier,
        }
    })
}

/// Find a `gfx::attrib::Type` that describes the given type identifier.
fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
               ty_ident: &ast::Ident, modifier: Option<Modifier>,
               path_root: ast::Ident) -> P<ast::Expr> {
    let ty_str = ty_ident.name.as_str();
    match ty_str {
        "f32" | "f64" => {
            let kind = cx.ident_of(match modifier {
                None | Some(Modifier::AsFloat) => "Default",
                Some(Modifier::AsDouble) => "Precision",
                Some(Modifier::Normalized) => {
                    cx.span_warn(span, &format!(
                        "Incompatible float modifier attribute: `#[{:?}]`", modifier
                    ));
                    ""
                }
            });
            let size = cx.ident_of(&format!("F{}", &ty_str[1..]));
            quote_expr!(cx, $path_root::gfx::attrib::Type::Float($path_root::gfx::attrib::FloatSubType::$kind,
                                                                 $path_root::gfx::attrib::FloatSize::$size))
        },
        "u8" | "u16" | "u32" | "u64" |
        "i8" | "i16" | "i32" | "i64" => {
            let sign = cx.ident_of({
                if ty_str.starts_with("i") { "Signed" } else { "Unsigned" }
            });
            let kind = cx.ident_of(match modifier {
                None => "Raw",
                Some(Modifier::Normalized) => "Normalized",
                Some(Modifier::AsFloat) => "AsFloat",
                Some(Modifier::AsDouble) => {
                    cx.span_warn(span, &format!(
                        "Incompatible int modifier attribute: `#[{:?}]`", modifier
                    ));
                    ""
                }
            });
            let size = cx.ident_of(&format!("U{}", &ty_str[1..]));
            quote_expr!(cx, $path_root::gfx::attrib::Type::Int($path_root::gfx::attrib::IntSubType::$kind,
                                                               $path_root::gfx::attrib::IntSize::$size,
                                                               $path_root::gfx::attrib::SignFlag::$sign))
        },
        ty_str => {
            cx.span_err(span, &format!("Unrecognized component type: `{:?}`",
                                      ty_str));
            cx.expr_tuple(span, vec![])
        },
    }
}

fn decode_count_and_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                         field: &ast::StructField,
                         path_root: ast::Ident) -> (P<ast::Expr>, P<ast::Expr>) {
    let modifier = find_modifier(cx, span, &field.node.attrs);
    match field.node.ty.node {
        ast::TyPath(_,ref p) => (
            cx.expr_lit(span, ast::LitInt(1, ast::UnsuffixedIntLit(ast::Plus))),
            decode_type(cx, span, &p.segments[0].identifier, modifier, path_root),
        ),
        ast::TyFixedLengthVec(ref pty, ref expr) => (expr.clone(), match pty.node {
            ast::TyPath(_,ref p) => {
                decode_type(cx, span, &p.segments[0].identifier, modifier, path_root)
            },
            _ => {
                cx.span_err(span, &format!("Unsupported fixed vector sub-type: \
                                          `{:?}`",pty.node));
                cx.expr_tuple(span, vec![])
            },
        }),
        _ => {
            cx.span_err(span, &format!("Unsupported attribute type: `{:?}`",
                                      field.node.ty.node));
            (cx.expr_tuple(span, vec![]), cx.expr_tuple(span, vec![]))
        },
    }
}

/// Generates the the method body for `gfx::VertexFormat::generate`.
fn method_body(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure,
                   path_root: ast::Ident) -> P<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let attribute_pushes = definition.fields.iter().zip(fields.iter())
                .map(|(def, &(ident, _))| {
                    let struct_ident = substr.type_ident;
                    let buffer_expr = &substr.nonself_args[0];
                    let (count_expr, type_expr) = decode_count_and_type(cx, span, def, path_root);
                    let ident_str = match super::find_name(cx, span, &def.node.attrs) {
                        Some(name) => name,
                        None => token::get_ident(ident),
                    };
                    let ident_str = &ident_str[..];
                    let instance_expr = cx.expr_u8(span, 0); // not supposed to be set by the macro
                    quote_expr!(cx, {
                        attributes.push($path_root::gfx::Attribute {
                            name: $ident_str.to_string(),
                            buffer: $buffer_expr.clone(),
                            format: $path_root::gfx::attrib::Format {
                                elem_count: $count_expr,
                                elem_type: $type_expr,
                                offset: unsafe {
                                    let x: $struct_ident = ::std::mem::uninitialized();
                                    let offset = (&x.$ident as *const _ as usize) -
                                        (&x as *const _ as usize);
                                    ::std::mem::forget(x);
                                    offset as $path_root::gfx::attrib::Offset
                                },
                                stride: { use std::mem;
                                    mem::size_of::<$struct_ident>() as
                                        $path_root::gfx::attrib::Stride
                                },
                                instance_rate: $instance_expr,
                            }
                        });
                    })
                }).collect::<Vec<P<ast::Expr>>>();
            let capacity = fields.len();
            quote_expr!(cx, {
                let mut attributes = Vec::with_capacity($capacity);
                $attribute_pushes;
                attributes
            })
        },
        _ => {
            cx.span_err(span, "Unable to implement `gfx::VertexFormat::generate` \
                              on a non-structure");
            cx.expr_tuple(span, vec![])
        }
    }
}

#[derive(Copy)]
pub struct VertexFormat;

impl ItemDecorator for VertexFormat {
    /// Derive a `gfx::VertexFormat` implementation for the `struct`
    fn expand(&self, context: &mut ext::base::ExtCtxt, span: codemap::Span,
              meta_item: &ast::MetaItem, item: &ast::Item,
              push: &mut FnMut(P<ast::Item>)) {
        // Insert the `gfx` reexport module
        let path_root = super::extern_crate_hack(context, span, |i| (*push)(i));
        let fixup = |item| {
            (*push)(super::fixup_extern_crate_paths(item, path_root))
        };

        // `impl<R: gfx::Resources> gfx::VertexFormat for $item`
        generic::TraitDef {
            span: span,
            attributes: Vec::new(),
            path: generic::ty::Path::new(
                vec![super::EXTERN_CRATE_HACK, "gfx", "VertexFormat"],
            ),
            additional_bounds: Vec::new(),
            generics: generic::ty::LifetimeBounds::empty(),
            methods: vec![
                // `fn generate(gfx::RawBufferHandle) -> Vec<gfx::Attribute>`
                generic::MethodDef {
                    name: "generate",
                    generics: generic::ty::LifetimeBounds {
                        lifetimes: Vec::new(),
                        bounds: vec![
                            ("R", vec![
                                generic::ty::Path::new(vec![
                                    super::EXTERN_CRATE_HACK, "gfx", "Resources"
                                ]),
                            ]),
                        ],
                    },
                    explicit_self: None,
                    args: vec![
                        generic::ty::Literal(generic::ty::Path {
                            path: vec![super::EXTERN_CRATE_HACK, "gfx", "RawBufferHandle"],
                            lifetime: None,
                            params: vec![box generic::ty::Literal(generic::ty::Path::new_local("R"))],
                            global: false,
                        }),
                    ],
                    ret_ty: generic::ty::Literal(
                        generic::ty::Path {
                            path: vec!["Vec"],
                            lifetime: None,
                            params: vec![
                                box generic::ty::Literal(generic::ty::Path {
                                    path: vec![super::EXTERN_CRATE_HACK, "gfx", "Attribute"],
                                    lifetime: None,
                                    params: vec![box generic::ty::Literal(
                                        generic::ty::Path::new_local("R")
                                    )],
                                    global: false,
                                }),
                            ],
                            global: false,
                        },
                    ),
                    attributes: Vec::new(),
                    // generate the method body
                    combine_substructure: generic::combine_substructure(
                        box |c, s, ss| method_body(c, s, ss, path_root)),
                },
            ],
            associated_types: Vec::new(),
        }.expand(context, meta_item, item, fixup);
    }
}
<|endoftext|>


<commit_before>use game::gfx::{CopySprite, Sprite};
use game::{Game};
use game::data::Rectangle;
use sdl2::render::Renderer;
use conv::prelude::*;
use sdl2::rect::Rect as SdlRect;

pub const TERRAIN_W: f64 = 500.0;
pub const TERRAIN_H: f64 = 250.0;

pub const TILES_PCS_W: usize = 160;
pub const TILES_PCS_H: usize = 100;

const TILES_W: f64 = 100.0;
const TILES_H: f64 = 50.0;

#[derive(Clone, Copy)]
pub enum TerrainFrame {
  Sand = 0,
  Grass = 1,
}

#[derive(Clone)]
pub struct TerrainTile {
  pub rect: Rectangle,
  pub terrain_sprites: Vec<Sprite>,
  pub current: TerrainFrame,
}

pub fn get_tiles(game: &Game) -> Vec<TerrainTile> {
  let terrain_spritesheet = Sprite::load(&game.renderer, "assets/terrain.png").unwrap();
  let mut terrain_sprites = Vec::with_capacity(TILES_PCS_W );
  let mut tiles = Vec::with_capacity(TILES_PCS_W * TILES_PCS_H * 2);

  for x in 0..3 {
    terrain_sprites.push(terrain_spritesheet.region(Rectangle {
      w: TILES_W,
      h: TILES_H,
      x: TILES_W * x as f64,
      y: 0.0 as f64,
    }).unwrap());
  }

  for x in 0..TILES_PCS_W {
    for y in 0..TILES_PCS_H {
      let x2: f64 = TILES_W * 1.5 as f64;
      let y2: f64 = TILES_H * 1.5 as f64;
      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * x as f64,
          y: TILES_H * y as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Grass,
      });

      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * f64::value_from((x + 1)).unwrap() - x2 as f64,
          y: TILES_H * f64::value_from((y + 1)).unwrap() - y2 as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Sand,
      });
    }
  }
  tiles
}

pub fn viewport_move(game: &Game, curr_rect: SdlRect) -> Rectangle {
  if game.events.move_right == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() - 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_left == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() + 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_up == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() + 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_down == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() - 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  }
}

#[derive(Clone)]
pub struct Tilemap {
  pub pos: f64,
  pub sprite: Sprite,
}
<commit_msg>Add cartesian_to_isometric function<commit_after>use game::gfx::{CopySprite, Sprite};
use game::{Game};
use game::data::Rectangle;
use sdl2::render::Renderer;
use conv::prelude::*;
use sdl2::rect::Rect as SdlRect;

pub const TERRAIN_W: f64 = 500.0;
pub const TERRAIN_H: f64 = 250.0;

pub const TILES_PCS_W: usize = 160;
pub const TILES_PCS_H: usize = 100;

const TILES_W: f64 = 100.0;
const TILES_H: f64 = 50.0;

#[derive(Clone, Copy)]
pub enum TerrainFrame {
  Sand = 0,
  Grass = 1,
}

#[derive(Clone)]
pub struct TerrainTile {
  pub rect: Rectangle,
  pub terrain_sprites: Vec<Sprite>,
  pub current: TerrainFrame,
}

#[derive(Clone)]
pub struct Tilemap {
  pub pos: f64,
  pub sprite: Sprite,
}

pub fn cartesian_to_isometric(point_x: i32, point_y: i32) -> (i32, i32) {
  let x = point_x - point_y;
  let y = (point_x + point_y) / 2;
  (x,y)
}

pub fn get_tiles(game: &Game) -> Vec<TerrainTile> {
  let terrain_spritesheet = Sprite::load(&game.renderer, "assets/terrain.png").unwrap();
  let mut terrain_sprites = Vec::with_capacity(TILES_PCS_W );
  let mut tiles = Vec::with_capacity(TILES_PCS_W * TILES_PCS_H * 2);

  for x in 0..3 {
    terrain_sprites.push(terrain_spritesheet.region(Rectangle {
      w: TILES_W,
      h: TILES_H,
      x: TILES_W * x as f64,
      y: 0.0 as f64,
    }).unwrap());
  }

  for x in 0..TILES_PCS_W {
    for y in 0..TILES_PCS_H {
      let x2: f64 = TILES_W * 1.5 as f64;
      let y2: f64 = TILES_H * 1.5 as f64;
      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * x as f64,
          y: TILES_H * y as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Grass,
      });

      tiles.push(TerrainTile {
        rect: Rectangle {
          x: TILES_W * f64::value_from((x + 1)).unwrap() - x2 as f64,
          y: TILES_H * f64::value_from((y + 1)).unwrap() - y2 as f64,
          w: TILES_W,
          h: TILES_H,
        },
        terrain_sprites: terrain_sprites.clone(),
        current: TerrainFrame::Sand,
      });
    }
  }
  tiles
}

pub fn viewport_move(game: &Game, curr_rect: SdlRect) -> Rectangle {
  if game.events.move_right == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() - 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_left == true {
    Rectangle {
      x: f64::value_from(curr_rect.x() + 3).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_up == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() + 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else if game.events.move_down == true {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y() - 3).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  } else {
    Rectangle {
      x: f64::value_from(curr_rect.x()).unwrap(),
      y: f64::value_from(curr_rect.y()).unwrap(),
      w: game.output_size().0 * 3.0,
      h: game.output_size().1 * 3.0,
    }
  }
}
<|endoftext|>


<commit_before>use core::CPU;
mod core;

fn setup_blank_cpu() -> CPU {
    CPU::new(Vec::from_elem(0x1, 0u8))
}

#[test]
fn check_address_converter() {
    let get_addr = CPU::to_addr;
    assert_eq!(get_addr(0x1, 0x2, 0x3), 0x123);
    assert_eq!(get_addr(0xF, 0xF, 0xF), 0xFFF);
    assert_eq!(get_addr(0x0, 0x0 ,0x0), 0x000);
}

#[test]
fn check_value_converter() {
    let get_val = CPU::to_val;
    assert_eq!(get_val( 0xF, 0xF), 0xFF);
    assert_eq!(get_val( 0x0, 0x0), 0x0);
    assert_eq!(get_val( 0x9, 0x5), 0x95);
}

#[test]
fn check_hex_to_digits_converter() {
    let get_vec = CPU::u16_to_hex_vec;
    assert_eq!(get_vec(0xFFFF), (0xF, 0xF, 0xF, 0xF));
    assert_eq!(get_vec(0x0000), (0x0, 0x0, 0x0, 0x0));
    assert_eq!(get_vec(0x0456), (0x0, 0x4, 0x5, 0x6));
}

#[test]
fn check_add_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6205); /* Load 0x5 into reg 2 */
    cpu.interpret(0x6510); /* Load 0x10 into reg 5 */
    cpu.interpret(0x8254); /* Add reg 5 to reg 2 and store in reg 2 */

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_reg(2), 0x15);
}

#[test]
fn check_add_regs_overlow_value() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x61FF); /* Load FF into reg 1 */
    cpu.interpret(0x62FF); /* Load FF into reg 2 */
    cpu.interpret(0x8124); /* Add reg2 to reg1 and store in reg 1 */

    assert_eq!(cpu.get_reg(0xF),  0x1); /* Check flag set */
    assert_eq!(cpu.get_reg(1), 0xFE);
}

/*** Test opcode 8XY5 ***/

/* Check a subtraction which results
 * in a value greater than zero */
#[test]
fn check_sub_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x64F0); /* Load F0 into reg 4 */
    cpu.interpret(0x6301); /* load 1 into reg 3 */
    cpu.interpret(0x8435); /* sub reg 3 from reg 4 and store in reg 4 */

    assert_eq!(cpu.get_reg(0xF), 0x1); /* check no overflow */
    assert_eq!(cpu.get_reg(4), 0xF0 - 0x1);

}

/* Check a subtraction which results
 * in a values less than zero */
#[test]
fn check_sub_regs_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6712); /* Load 0x12 into reg 7 */
    cpu.interpret(0x6920); /* Load 020 into reg 9 */
    cpu.interpret(0x8795); /* sub r9 from r7 store result in r7 */

    assert_eq!(cpu.get_reg(0xF), 0x0); /* check overflow */
    assert_eq!(cpu.get_reg(0x7), (0x12 - 0x20) as u8);

}

/*** Test opcode 8XY7, subbing registers ***
 *** the other way round than from 8XY5  ***/

/* Check a subtraction which results
 * in a value greater than zero */
#[test]
fn check_sub_inverted_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6A23);
    cpu.interpret(0x6B30);
    cpu.interpret(0x8AB7);

    assert_eq!(cpu.get_reg(0xF), 0x1);
    assert_eq!(cpu.get_reg(0xA), 0x30 - 0x23);
}

/* Check a subtraction which results
 * in a value less than zero */
#[test]
fn check_sub_inverted_regs_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6CD3);
    cpu.interpret(0x6E30);
    cpu.interpret(0x8CE7);

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_reg(0xC), (0x30 - 0xD3) as u8);
}

#[test]
fn check_index_add_reg() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0xA111); //set I to 0x111
    cpu.interpret(0x6120); // set reg 1 to 20
    cpu.interpret(0xF11E); // Add reg 1 to I

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_index_reg(), 0x20 + 0x111);
}

#[test]
fn check_index_add_reg_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0xAFFF); //set I to 0xFFF
    cpu.interpret(0x6C56); // set reg C to 0x56
    cpu.interpret(0xFC1E); // Add reg C to I

    assert_eq!(cpu.get_reg(0xF), 0x1);
    assert_eq!(cpu.get_index_reg(), (0xFFF + 0x056) % 0x1000);
}

/*** Jump instructions */

/*** Check instruction 3XNN ***/

/* Check skip occurs if
 * reg equals value */
#[test]
fn check_skip_reg_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6544); /* set reg 5 to 0x44 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x3544);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur
 * if reg doesn't equal value */
#[test]
fn check_no_skip_reg_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6067); /* set reg 0 to 0x67 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x3081);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 4XNN ***/

/*Check skip occurs if
 * reg not equal to value */
#[test]
fn check_skip_reg_not_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6794); /* set reg 7 to 0x94 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x4700);
    assert_eq!(cpu.get_pc(), before_pc + 4);

}

/* Check skip doesn't occur if
 * reg  equals value  */
#[test]
fn check_no_skip_reg_not_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6DAB); /* set reg D to 0xAB */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x4DAB);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 5XY0 ***/

/* Check skip occurs if
 * registers contain the same value */
#[test]
fn check_skip_regs_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6CF2); /* set reg C to 0xF2 */
    cpu.interpret(0x69F2); /* set reg 9 to 0xF2 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5C90);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur
 * if registers don't contain
 * the same value */
#[test]
fn check_no_skip_regs_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6A71); /* set reg A to 0x71 */
    cpu.interpret(0x69BA); /* set reg 9 to 0xBA */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5A90);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 9XY0 ***/

/* Check skip occurs when regsisters
 * not equal */
#[test]
fn check_skip_regs_not_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6661); /* set reg 6 to 0x66 */
    cpu.interpret(0xEEE); /* set reg E to 0xEE */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x96E0);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur when registers
 * are equal */
#[test]
fn check_no_skip_regs_not_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6555); /* set reg 5 to 0x55 */
    cpu.interpret(0x6DDD); /* set reg D to 0xDD */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5D0);
    assert_eq!(cpu.get_pc(), before_pc + 2);

}

/*** Check instruction BNNN ***/

#[test]
fn check_address_add_r0() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6043);
    cpu.interpret(0xB151);
    assert_eq!(cpu.get_pc(), 0x043 + 0x151);

}

<commit_msg>Added test covering jump/skip instructions<commit_after>use core::CPU;
mod core;

fn setup_blank_cpu() -> CPU {
    CPU::new(Vec::from_elem(0x1, 0u8))
}

#[test]
fn check_address_converter() {
    let get_addr = CPU::to_addr;
    assert_eq!(get_addr(0x1, 0x2, 0x3), 0x123);
    assert_eq!(get_addr(0xF, 0xF, 0xF), 0xFFF);
    assert_eq!(get_addr(0x0, 0x0 ,0x0), 0x000);
}

#[test]
fn check_value_converter() {
    let get_val = CPU::to_val;
    assert_eq!(get_val( 0xF, 0xF), 0xFF);
    assert_eq!(get_val( 0x0, 0x0), 0x0);
    assert_eq!(get_val( 0x9, 0x5), 0x95);
}

#[test]
fn check_hex_to_digits_converter() {
    let get_vec = CPU::u16_to_hex_vec;
    assert_eq!(get_vec(0xFFFF), (0xF, 0xF, 0xF, 0xF));
    assert_eq!(get_vec(0x0000), (0x0, 0x0, 0x0, 0x0));
    assert_eq!(get_vec(0x0456), (0x0, 0x4, 0x5, 0x6));
}

#[test]
fn check_add_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6205); /* Load 0x5 into reg 2 */
    cpu.interpret(0x6510); /* Load 0x10 into reg 5 */
    cpu.interpret(0x8254); /* Add reg 5 to reg 2 and store in reg 2 */

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_reg(2), 0x15);
}

#[test]
fn check_add_regs_overlow_value() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x61FF); /* Load FF into reg 1 */
    cpu.interpret(0x62FF); /* Load FF into reg 2 */
    cpu.interpret(0x8124); /* Add reg2 to reg1 and store in reg 1 */

    assert_eq!(cpu.get_reg(0xF),  0x1); /* Check flag set */
    assert_eq!(cpu.get_reg(1), 0xFE);
}

/*** Test opcode 8XY5 ***/

/* Check a subtraction which results
 * in a value greater than zero */
#[test]
fn check_sub_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x64F0); /* Load F0 into reg 4 */
    cpu.interpret(0x6301); /* load 1 into reg 3 */
    cpu.interpret(0x8435); /* sub reg 3 from reg 4 and store in reg 4 */

    assert_eq!(cpu.get_reg(0xF), 0x1); /* check no overflow */
    assert_eq!(cpu.get_reg(4), 0xF0 - 0x1);

}

/* Check a subtraction which results
 * in a values less than zero */
#[test]
fn check_sub_regs_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6712); /* Load 0x12 into reg 7 */
    cpu.interpret(0x6920); /* Load 020 into reg 9 */
    cpu.interpret(0x8795); /* sub r9 from r7 store result in r7 */

    assert_eq!(cpu.get_reg(0xF), 0x0); /* check overflow */
    assert_eq!(cpu.get_reg(0x7), (0x12 - 0x20) as u8);

}

/*** Test opcode 8XY7, subbing registers ***
 *** the other way round than from 8XY5  ***/

/* Check a subtraction which results
 * in a value greater than zero */
#[test]
fn check_sub_inverted_regs() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6A23);
    cpu.interpret(0x6B30);
    cpu.interpret(0x8AB7);

    assert_eq!(cpu.get_reg(0xF), 0x1);
    assert_eq!(cpu.get_reg(0xA), 0x30 - 0x23);
}

/* Check a subtraction which results
 * in a value less than zero */
#[test]
fn check_sub_inverted_regs_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6CD3);
    cpu.interpret(0x6E30);
    cpu.interpret(0x8CE7);

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_reg(0xC), (0x30 - 0xD3) as u8);
}

#[test]
fn check_index_add_reg() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0xA111); //set I to 0x111
    cpu.interpret(0x6120); // set reg 1 to 20
    cpu.interpret(0xF11E); // Add reg 1 to I

    assert_eq!(cpu.get_reg(0xF), 0x0);
    assert_eq!(cpu.get_index_reg(), 0x20 + 0x111);
}

#[test]
fn check_index_add_reg_overflow() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0xAFFF); //set I to 0xFFF
    cpu.interpret(0x6C56); // set reg C to 0x56
    cpu.interpret(0xFC1E); // Add reg C to I

    assert_eq!(cpu.get_reg(0xF), 0x1);
    assert_eq!(cpu.get_index_reg(), (0xFFF + 0x056) % 0x1000);
}

/*** Jump instructions */

/*** Check instruction 3XNN ***/

/* Check skip occurs if
 * reg equals value */
#[test]
fn check_skip_reg_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6544); /* set reg 5 to 0x44 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x3544);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur
 * if reg doesn't equal value */
#[test]
fn check_no_skip_reg_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6067); /* set reg 0 to 0x67 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x3081);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 4XNN ***/

/*Check skip occurs if
 * reg not equal to value */
#[test]
fn check_skip_reg_not_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6794); /* set reg 7 to 0x94 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x4700);
    assert_eq!(cpu.get_pc(), before_pc + 4);

}

/* Check skip doesn't occur if
 * reg  equals value  */
#[test]
fn check_no_skip_reg_not_equals_val() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6DAB); /* set reg D to 0xAB */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x4DAB);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 5XY0 ***/

/* Check skip occurs if
 * registers contain the same value */
#[test]
fn check_skip_regs_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6CF2); /* set reg C to 0xF2 */
    cpu.interpret(0x69F2); /* set reg 9 to 0xF2 */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5C90);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur
 * if registers don't contain
 * the same value */
#[test]
fn check_no_skip_regs_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6A71); /* set reg A to 0x71 */
    cpu.interpret(0x69BA); /* set reg 9 to 0xBA */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5A90);
    assert_eq!(cpu.get_pc(), before_pc + 2);
}

/*** Check instruction 9XY0 ***/

/* Check skip occurs when regsisters
 * not equal */
#[test]
fn check_skip_regs_not_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6661); /* set reg 6 to 0x66 */
    cpu.interpret(0xEEE); /* set reg E to 0xEE */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x96E0);
    assert_eq!(cpu.get_pc(), before_pc + 4);
}

/* Check skip doesn't occur when registers
 * are equal */
#[test]
fn check_no_skip_regs_not_equal() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6555); /* set reg 5 to 0x55 */
    cpu.interpret(0x6DDD); /* set reg D to 0xDD */
    let before_pc = cpu.get_pc();
    cpu.interpret(0x5D0);
    assert_eq!(cpu.get_pc(), before_pc + 2);

}

/*** Check instruction BNNN ***/

#[test]
fn check_address_add_r0() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x6043);
    cpu.interpret(0xB151);
    assert_eq!(cpu.get_pc(), 0x043 + 0x151);

}

#[test]
/*** Check instruction 1NNN ***/
fn check_jump() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x1FFF);
    assert_eq!(cpu.get_pc(), 0xFFF);
}

#[test]
/*** Check instruction 2NNN ***/
fn check_call() {
    let mut cpu = setup_blank_cpu();
    cpu.interpret(0x2342);
    assert_eq!(cpu.get_pc(), 0x342);
}

#[test]
fn check_return() {
    let mut cpu = setup_blank_cpu();
    let before_pc = cpu.get_pc();
    cpu.interpret(0x2268);
    cpu.interpret(0x00EE);
    assert_eq!(cpu.get_pc(), before_pc + 2);

}

<|endoftext|>


<commit_before>use nom::{IResult, Offset, Slice};
use std::ops::RangeTo;

/// Wright literal value parsers.
pub(crate) mod literals;

/// Wright expression parsers.
pub(crate) mod expression;

/// Wright comment and whitespace parsers.
pub(crate) mod whitespace;

/// Whitespace module tests
mod whitespace_tests;

/// Call a parser and on success, return the input consumed as well as the
/// result.
/// This function essentially returns a copy of the parser that returns
/// `(I, (I, O))`, or `(remaining input, (input consumed, output))`
pub fn with_input<F, I, O>(parser: F) -> impl Fn(I) -> IResult<I, (I, O)>
    where
        I: Clone + Offset + Slice<RangeTo<usize>>,
        F: Fn(I) -> IResult<I, O> {
    move |input: I| -> IResult<I, (I, O)> {
        let i = input.clone();
        match parser(i) {
            Ok((remaining, result)) => {
                let index = input.offset(&remaining);
                Ok((remaining, (input.slice(..index), result)))
            },
            Err(e) => Err(e)
        }
    }
}<commit_msg>test with_input<commit_after>use nom::{IResult, Offset, Slice};
use std::ops::RangeTo;

/// Wright literal value parsers.
pub(crate) mod literals;

/// Wright expression parsers.
pub(crate) mod expression;

/// Wright comment and whitespace parsers.
pub(crate) mod whitespace;

/// Whitespace module tests
mod whitespace_tests;

/// Call a parser and on success, return the input consumed as well as the
/// result.
/// This function essentially returns a copy of the parser that returns
/// `(I, (I, O))`, or `(remaining input, (input consumed, output))`
pub fn with_input<F, I, O>(parser: F) -> impl Fn(I) -> IResult<I, (I, O)>
    where
        I: Clone + Offset + Slice<RangeTo<usize>>,
        F: Fn(I) -> IResult<I, O> {
    move |input: I| -> IResult<I, (I, O)> {
        let i = input.clone();
        match parser(i) {
            Ok((remaining, result)) => {
                let index = input.offset(&remaining);
                Ok((remaining, (input.slice(..index), result)))
            },
            Err(e) => Err(e)
        }
    }
}

#[cfg(test)]
mod with_input_test {
    use nom::bytes::complete::tag;
    use crate::grammar::parsers::with_input;

    #[test]
    fn test_with_input() {
        let parser = tag("abc");
        match with_input(parser)("abcdef") {
            Ok((rem, (consumed,res))) => {
                assert_eq!(rem, "def");
                assert_eq!(consumed, "abc");
                assert_eq!(res, "abc");
            },
            Err(e) => panic!(e)
        }

    }
}<|endoftext|>


<commit_before>
use std::error::Error as StdError;
use std::fmt;

#[derive(PartialEq)]
pub enum ParseError {
    Eof,
    NotFound,
    Expected(Vec<u8>),
    ExpectedType(&'static str),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof => "End of File",
            ParseError::NotFound => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
            ParseError::ExpectedType(_) => "Expectation Failed",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Eof => None,
            ParseError::NotFound => None,
            ParseError::Expected(_) => None,
            ParseError::ExpectedType(_) => None,
        }
    }
}
<commit_msg>rfc5322: ParseError::Io<commit_after>
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IoError;

pub enum ParseError {
    Eof,
    NotFound,
    Expected(Vec<u8>),
    ExpectedType(&'static str),
    Io(IoError),
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            ParseError::Io(ref e) => write!(f, "{}: {}",
                                             self.description(), e),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl fmt::Debug for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>
    {
        match *self {
            ParseError::Expected(ref bytes) => write!(f, "{}. Expected {:?}",
                                                      self.description(), bytes),
            ParseError::ExpectedType(ref t) => write!(f, "{}. Expected {}",
                                                      self.description(), t),
            ParseError::Io(ref e) => write!(f, "{}: {:?}",
                                             self.description(), e),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl StdError for ParseError {
    fn description(&self) -> &str
    {
        match *self {
            ParseError::Eof => "End of File",
            ParseError::NotFound => "Not Found",
            ParseError::Expected(_) => "Expectation Failed",
            ParseError::ExpectedType(_) => "Expectation Failed",
            ParseError::Io(_) => "I/O Error",
        }
    }

    fn cause(&self) -> Option<&StdError>
    {
        match *self {
            ParseError::Eof => None,
            ParseError::NotFound => None,
            ParseError::Expected(_) => None,
            ParseError::ExpectedType(_) => None,
            ParseError::Io(ref e) => Some(e),
        }
    }
}
<|endoftext|>