<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError, MissingFieldError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    } else {
        info!("finished executing the '{}' action", demand.action);
    }

    let message = match session.status(result).try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response + 'static;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response + 'static;

    /// Sends a heartbeat signal to the Fleetspeak process.
    fn heartbeat(&mut self) {
        // TODO: Create a real implementation.
    }
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        // Response identifiers that GRR agents use start at 1. Unfortunately,
        // the server uses this assumption (to determine the number of expected
        // responses when status message is received), so we have to follow this
        // behaviour in RRG as well.
        Action {
            header: demand.header.clone(),
            next_response_id: 1,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }

    /// Wraps an action result to a session-specific status response.
    ///
    /// Note that this method consumes the session. The reason for this is that
    /// status response should be obtained as the very last response and no
    /// further replies should be possible after that.
    fn status(self, result: Result<()>) -> Status {
        Status {
            session_id: self.header.session_id,
            request_id: self.header.request_id,
            response_id: self.next_response_id,
            result: result,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}

#[cfg(test)]
pub mod test {
    use std::any::Any;
    use std::collections::HashMap;

    use super::*;

    /// A session type intended to be used in tests.
    ///
    /// Testing actions with normal session objects can be quite hard, since
    /// they communicate with the outside world (through Fleetspeak). Since we
    /// want to keep the tests minimal and not waste resources on unneeded I/O,
    /// using real sessions is not an option.
    ///
    /// Instead, one can use a `Fake` session. It simply accumulates responses
    /// that the action sends and lets the creator inspect them later.
    pub struct Fake {
        replies: Vec<Box<dyn Any>>,
        responses: HashMap<Sink, Vec<Box<dyn Any>>>,
    }

    impl Fake {

        /// Constructs a new fake session.
        pub fn new() -> Fake {
            Fake {
                replies: Vec::new(),
                responses: std::collections::HashMap::new(),
            }
        }

        /// Yields the number of replies that this session sent so far.
        pub fn reply_count(&self) -> usize {
            self.replies.len()
        }

        /// Retrieves a reply corresponding to the given id.
        ///
        /// The identifier corresponding to the first response is 0, the second
        /// one is 1 and so on.
        ///
        /// This method will panic if a reply with the specified `id` does not
        /// exist or if it exists but has a wrong type.
        pub fn reply<R>(&self, id: usize) -> &R
        where
            R: action::Response + 'static,
        {
            match self.replies::<R>().nth(id) {
                Some(reply) => reply,
                None => panic!("no reply #{}", id),
            }
        }

        pub fn replies<R>(&self) -> impl Iterator<Item = &R>
        where
            R: action::Response + 'static
        {
            self.replies.iter().map(|reply| {
                reply.downcast_ref().expect("unexpected reply type")
            })
        }

        /// Yields the number of responses sent so far to the specified sink.
        pub fn response_count(&self, sink: Sink) -> usize {
            match self.responses.get(&sink) {
                Some(responses) => responses.len(),
                None => 0,
            }
        }

        /// Retrieves a response with the given id sent to a particular sink.
        ///
        /// The identifier corresponding to the first response to the particular
        /// sink is 0, to the second one (to the same sink) is 1 and so on.
        ///
        /// This method will panic if a reply with the specified `id` to the
        /// given `sink` does not exist or if it exists but has wrong type.
        pub fn response<R>(&self, sink: Sink, id: usize) -> &R
        where
            R: action::Response + 'static,
        {
            match self.responses::<R>(sink).nth(id) {
                Some(response) => response,
                None => panic!("no response #{} for sink '{:?}'", id, sink),
            }
        }

        pub fn responses<R>(&self, sink: Sink) -> impl Iterator<Item = &R>
        where
            R: action::Response + 'static,
        {
            // Since the empty iterator (as defined in the standard library) is
            // a specific type, it cannot be returned in one branch but not in
            // another branch.
            //
            // Instead, we use the fact that `Option` is an iterator and then we
            // squash it with `Iterator::flat_map`.
            let responses = self.responses.get(&sink)
                .into_iter()
                .flat_map(std::convert::identity);

            responses.map(move |response| match response.downcast_ref() {
                Some(response) => response,
                None => panic!("unexpected response type in sink '{:?}'", sink),
            })
        }
    }

    impl Session for Fake {

        fn reply<R>(&mut self, response: R) -> Result<()>
        where
            R: action::Response + 'static,
        {
            self.replies.push(Box::new(response));

            Ok(())
        }

        fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
        where
            R: action::Response + 'static,
        {
            let responses = self.responses.entry(sink).or_insert_with(Vec::new);
            responses.push(Box::new(response));

            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_fake_reply_count() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(()).unwrap();
            session.reply(()).unwrap();
            session.reply(()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.reply_count(), 3);
    }

    #[test]
    fn test_fake_response_count() {

        // TODO: Extend this test with more sinks (once we have some more sinks
        // defined).

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, ()).unwrap();
            session.send(Sink::STARTUP, ()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.response_count(Sink::STARTUP), 2);
    }

    #[test]
    fn test_fake_reply_correct_response() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(StringResponse::from("foo")).unwrap();
            session.reply(StringResponse::from("bar")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.reply::<StringResponse>(0).0, "foo");
        assert_eq!(session.reply::<StringResponse>(1).0, "bar");
    }

    #[test]
    #[should_panic(expected = "no reply #0")]
    fn test_fake_reply_incorrect_response_id() {

        fn handle<S: Session>(_: &mut S, _: ()) {
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.reply::<()>(0);
    }

    #[test]
    #[should_panic(expected = "unexpected reply type")]
    fn test_fake_reply_incorrect_response_type() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(StringResponse::from("quux")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.reply::<()>(0);
    }

    #[test]
    fn test_fake_response_correct_response() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, StringResponse::from("foo")).unwrap();
            session.send(Sink::STARTUP, StringResponse::from("bar")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        let response_foo = session.response::<StringResponse>(Sink::STARTUP, 0);
        let response_bar = session.response::<StringResponse>(Sink::STARTUP, 1);
        assert_eq!(response_foo.0, "foo");
        assert_eq!(response_bar.0, "bar");
    }

    #[test]
    #[should_panic(expected = "no response #42")]
    fn test_fake_response_incorrect_response_id() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, ()).unwrap();
            session.send(Sink::STARTUP, ()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.response::<()>(Sink::STARTUP, 42);
    }

    #[test]
    #[should_panic(expected = "unexpected response type")]
    fn test_fake_response_incorrect_response_type() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, StringResponse::from("quux")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.response::<()>(Sink::STARTUP, 0);
    }

    struct StringResponse(String);

    impl<S: Into<String>> From<S> for StringResponse {

        fn from(string: S) -> StringResponse {
            StringResponse(string.into())
        }
    }

    impl action::Response for StringResponse {

        const RDF_NAME: Option<&'static str> = Some("RDFString");

        type Proto = String;

        fn into_proto(self) -> String {
            self.0
        }
    }
}
<commit_msg>Remove unnecessary type annotations.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError, MissingFieldError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    } else {
        info!("finished executing the '{}' action", demand.action);
    }

    let message = match session.status(result).try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response + 'static;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response + 'static;

    /// Sends a heartbeat signal to the Fleetspeak process.
    fn heartbeat(&mut self) {
        // TODO: Create a real implementation.
    }
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        // Response identifiers that GRR agents use start at 1. Unfortunately,
        // the server uses this assumption (to determine the number of expected
        // responses when status message is received), so we have to follow this
        // behaviour in RRG as well.
        Action {
            header: demand.header.clone(),
            next_response_id: 1,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }

    /// Wraps an action result to a session-specific status response.
    ///
    /// Note that this method consumes the session. The reason for this is that
    /// status response should be obtained as the very last response and no
    /// further replies should be possible after that.
    fn status(self, result: Result<()>) -> Status {
        Status {
            session_id: self.header.session_id,
            request_id: self.header.request_id,
            response_id: self.next_response_id,
            result: result,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}

#[cfg(test)]
pub mod test {
    use std::any::Any;
    use std::collections::HashMap;

    use super::*;

    /// A session type intended to be used in tests.
    ///
    /// Testing actions with normal session objects can be quite hard, since
    /// they communicate with the outside world (through Fleetspeak). Since we
    /// want to keep the tests minimal and not waste resources on unneeded I/O,
    /// using real sessions is not an option.
    ///
    /// Instead, one can use a `Fake` session. It simply accumulates responses
    /// that the action sends and lets the creator inspect them later.
    pub struct Fake {
        replies: Vec<Box<dyn Any>>,
        responses: HashMap<Sink, Vec<Box<dyn Any>>>,
    }

    impl Fake {

        /// Constructs a new fake session.
        pub fn new() -> Fake {
            Fake {
                replies: Vec::new(),
                responses: std::collections::HashMap::new(),
            }
        }

        /// Yields the number of replies that this session sent so far.
        pub fn reply_count(&self) -> usize {
            self.replies.len()
        }

        /// Retrieves a reply corresponding to the given id.
        ///
        /// The identifier corresponding to the first response is 0, the second
        /// one is 1 and so on.
        ///
        /// This method will panic if a reply with the specified `id` does not
        /// exist or if it exists but has a wrong type.
        pub fn reply<R>(&self, id: usize) -> &R
        where
            R: action::Response + 'static,
        {
            match self.replies().nth(id) {
                Some(reply) => reply,
                None => panic!("no reply #{}", id),
            }
        }

        pub fn replies<R>(&self) -> impl Iterator<Item = &R>
        where
            R: action::Response + 'static
        {
            self.replies.iter().map(|reply| {
                reply.downcast_ref().expect("unexpected reply type")
            })
        }

        /// Yields the number of responses sent so far to the specified sink.
        pub fn response_count(&self, sink: Sink) -> usize {
            match self.responses.get(&sink) {
                Some(responses) => responses.len(),
                None => 0,
            }
        }

        /// Retrieves a response with the given id sent to a particular sink.
        ///
        /// The identifier corresponding to the first response to the particular
        /// sink is 0, to the second one (to the same sink) is 1 and so on.
        ///
        /// This method will panic if a reply with the specified `id` to the
        /// given `sink` does not exist or if it exists but has wrong type.
        pub fn response<R>(&self, sink: Sink, id: usize) -> &R
        where
            R: action::Response + 'static,
        {
            match self.responses(sink).nth(id) {
                Some(response) => response,
                None => panic!("no response #{} for sink '{:?}'", id, sink),
            }
        }

        pub fn responses<R>(&self, sink: Sink) -> impl Iterator<Item = &R>
        where
            R: action::Response + 'static,
        {
            // Since the empty iterator (as defined in the standard library) is
            // a specific type, it cannot be returned in one branch but not in
            // another branch.
            //
            // Instead, we use the fact that `Option` is an iterator and then we
            // squash it with `Iterator::flat_map`.
            let responses = self.responses.get(&sink)
                .into_iter()
                .flat_map(std::convert::identity);

            responses.map(move |response| match response.downcast_ref() {
                Some(response) => response,
                None => panic!("unexpected response type in sink '{:?}'", sink),
            })
        }
    }

    impl Session for Fake {

        fn reply<R>(&mut self, response: R) -> Result<()>
        where
            R: action::Response + 'static,
        {
            self.replies.push(Box::new(response));

            Ok(())
        }

        fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
        where
            R: action::Response + 'static,
        {
            let responses = self.responses.entry(sink).or_insert_with(Vec::new);
            responses.push(Box::new(response));

            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_fake_reply_count() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(()).unwrap();
            session.reply(()).unwrap();
            session.reply(()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.reply_count(), 3);
    }

    #[test]
    fn test_fake_response_count() {

        // TODO: Extend this test with more sinks (once we have some more sinks
        // defined).

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, ()).unwrap();
            session.send(Sink::STARTUP, ()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.response_count(Sink::STARTUP), 2);
    }

    #[test]
    fn test_fake_reply_correct_response() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(StringResponse::from("foo")).unwrap();
            session.reply(StringResponse::from("bar")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        assert_eq!(session.reply::<StringResponse>(0).0, "foo");
        assert_eq!(session.reply::<StringResponse>(1).0, "bar");
    }

    #[test]
    #[should_panic(expected = "no reply #0")]
    fn test_fake_reply_incorrect_response_id() {

        fn handle<S: Session>(_: &mut S, _: ()) {
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.reply::<()>(0);
    }

    #[test]
    #[should_panic(expected = "unexpected reply type")]
    fn test_fake_reply_incorrect_response_type() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.reply(StringResponse::from("quux")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.reply::<()>(0);
    }

    #[test]
    fn test_fake_response_correct_response() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, StringResponse::from("foo")).unwrap();
            session.send(Sink::STARTUP, StringResponse::from("bar")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        let response_foo = session.response::<StringResponse>(Sink::STARTUP, 0);
        let response_bar = session.response::<StringResponse>(Sink::STARTUP, 1);
        assert_eq!(response_foo.0, "foo");
        assert_eq!(response_bar.0, "bar");
    }

    #[test]
    #[should_panic(expected = "no response #42")]
    fn test_fake_response_incorrect_response_id() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, ()).unwrap();
            session.send(Sink::STARTUP, ()).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.response::<()>(Sink::STARTUP, 42);
    }

    #[test]
    #[should_panic(expected = "unexpected response type")]
    fn test_fake_response_incorrect_response_type() {

        fn handle<S: Session>(session: &mut S, _: ()) {
            session.send(Sink::STARTUP, StringResponse::from("quux")).unwrap();
        }

        let mut session = test::Fake::new();
        handle(&mut session, ());

        session.response::<()>(Sink::STARTUP, 0);
    }

    struct StringResponse(String);

    impl<S: Into<String>> From<S> for StringResponse {

        fn from(string: S) -> StringResponse {
            StringResponse(string.into())
        }
    }

    impl action::Response for StringResponse {

        const RDF_NAME: Option<&'static str> = Some("RDFString");

        type Proto = String;

        fn into_proto(self) -> String {
            self.0
        }
    }
}
<|endoftext|>


<commit_before>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;
use log::error;

use crate::action;
pub use self::error::{Error, ParseError};

pub type Result<T> = std::result::Result<T, Error>;

pub fn execute<S, R, H>(session: &mut S, handler: H, payload: Payload) -> Result<()>
where
    S: Session,
    R: action::Request,
    H: FnOnce(&mut S, R) -> Result<()>,
{
    handler(session, payload.parse()?)
}

pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => demand,
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::new(demand.header.clone());

    // TODO: Send status message.
    let _result = action::dispatch(&demand.action, &mut session, demand.payload);
}

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    pub fn new(header: Header) -> Action {
        Action {
            header: header,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

pub struct Demand {
    pub action: String,
    pub header: Header,
    pub payload: Payload,
}

impl TryFrom<rrg_proto::GrrMessage> for Demand {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Demand, ParseError>
    {
        use ParseError::*;

        let header = Header {
            session_id: message.session_id.ok_or(MissingField("session id"))?,
            request_id: message.request_id.ok_or(MissingField("request id"))?,
        };

        Ok(Demand {
            action: message.name.ok_or(MissingField("action name"))?,
            header: header,
            payload: Payload(message.args),
        })
    }
}

#[derive(Clone, Debug)]
pub struct Header {
    pub session_id: String,
    pub request_id: u64,
}

#[derive(Debug)]
pub struct Payload(Option<Vec<u8>>);

impl Payload {

    pub fn parse<R>(&self) -> std::result::Result<R, ParseError>
    where
        R: action::Request,
    {
        let proto = match self {
            Payload(Some(bytes)) => prost::Message::decode(&bytes[..])?,
            Payload(None) => Default::default(),
        };

        Ok(R::from_proto(proto))
    }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, ParseError>
    {
        use ParseError::*;

        let name = message.name.ok_or(MissingField("action name"))?;
        let session_id = message.session_id.ok_or(MissingField("session id"))?;
        let request_id = message.request_id.ok_or(MissingField("request id"))?;

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let message: rrg_proto::GrrMessage = self.try_into()?;

        let packet = Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: message,
        };

        use fleetspeak::WriteError::*;
        match fleetspeak::send(packet) {
            Ok(()) => Ok(()),
            Err(Encode(error)) => Err(error.into()),
            Err(Output(error)) => {
                // If we failed to deliver the message through Fleetspeak, it
                // means that our communication is broken (e.g. the pipe was
                // closed) and the agent should be killed.
                panic!("message delivery failure: {}", error)
            }
        }
    }
}

impl<R: action::Response> TryInto<rrg_proto::GrrMessage> for Response<R> {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError>
    {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        })
    }
}

struct Status {
    session_id: String,
    request_id: u64,
    result: Result<()>,
}

impl TryInto<rrg_proto::GrrMessage> for Status {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError> {
        let status = match self.result {
            Ok(()) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::Ok.into()),
                ..Default::default()
            },
            Err(error) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::GenericError.into()),
                error_message: Some(error.to_string()),
                ..Default::default()
            },
        };

        let mut data = Vec::new();
        prost::Message::encode(&status, &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: Some(self.request_id),
            r#type: Some(rrg_proto::grr_message::Type::Status.into()),
            args_rdf_name: Some(String::from("GrrStatus")),
            args: Some(data),
            ..Default::default()
        })
    }
}
<commit_msg>Move packet sending to a separate function.<commit_after>mod error;

use std::convert::{TryFrom, TryInto};

use fleetspeak::Packet;
use log::error;

use crate::action;
pub use self::error::{Error, ParseError};

pub type Result<T> = std::result::Result<T, Error>;

pub fn execute<S, R, H>(session: &mut S, handler: H, payload: Payload) -> Result<()>
where
    S: Session,
    R: action::Request,
    H: FnOnce(&mut S, R) -> Result<()>,
{
    handler(session, payload.parse()?)
}

pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => demand,
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::new(demand.header.clone());

    // TODO: Send status message.
    let _result = action::dispatch(&demand.action, &mut session, demand.payload);
}

pub trait Session {
    fn send<R: action::Response>(&mut self, response: R) -> Result<()>;
}

pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    pub fn new(header: Header) -> Action {
        Action {
            header: header,
            next_response_id: 0,
        }
    }
}

impl Session for Action {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }.send()?;

        self.next_response_id += 1;

        Ok(())
    }
}

pub struct Sink {
    id: &'static str,
}

impl Session for Sink {

    fn send<R: action::Response>(&mut self, response: R) -> Result<()> {
        Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }.send()
    }
}

pub fn startup() -> Sink {
    Sink { id: "/flows/F:Startup" }
}

pub struct Demand {
    pub action: String,
    pub header: Header,
    pub payload: Payload,
}

impl TryFrom<rrg_proto::GrrMessage> for Demand {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Demand, ParseError>
    {
        use ParseError::*;

        let header = Header {
            session_id: message.session_id.ok_or(MissingField("session id"))?,
            request_id: message.request_id.ok_or(MissingField("request id"))?,
        };

        Ok(Demand {
            action: message.name.ok_or(MissingField("action name"))?,
            header: header,
            payload: Payload(message.args),
        })
    }
}

#[derive(Clone, Debug)]
pub struct Header {
    pub session_id: String,
    pub request_id: u64,
}

#[derive(Debug)]
pub struct Payload(Option<Vec<u8>>);

impl Payload {

    pub fn parse<R>(&self) -> std::result::Result<R, ParseError>
    where
        R: action::Request,
    {
        let proto = match self {
            Payload(Some(bytes)) => prost::Message::decode(&bytes[..])?,
            Payload(None) => Default::default(),
        };

        Ok(R::from_proto(proto))
    }
}

// TODO: This type should not be exposed.
pub struct Request<R: action::Request> {
    pub name: String,
    pub session_id: String,
    pub request_id: u64,
    pub data: R,
}

impl<R: action::Request> TryFrom<rrg_proto::GrrMessage> for Request<R> {

    type Error = ParseError;

    fn try_from(message: rrg_proto::GrrMessage)
    -> std::result::Result<Request<R>, ParseError>
    {
        use ParseError::*;

        let name = message.name.ok_or(MissingField("action name"))?;
        let session_id = message.session_id.ok_or(MissingField("session id"))?;
        let request_id = message.request_id.ok_or(MissingField("request id"))?;

        let proto = match message.args {
            Some(bytes) => prost::Message::decode(&bytes[..])?,
            None => Default::default(),
        };

        Ok(Request {
            name: name,
            session_id: session_id,
            request_id: request_id,
            data: R::from_proto(proto),
        })
    }
}

struct Response<R: action::Response> {
    session_id: String,
    request_id: Option<u64>,
    response_id: Option<u64>,
    data: R,
}

impl<R: action::Response> Response<R> {

    fn send(self) -> Result<()> {
        let message = self.try_into()?;
        send(message);

        Ok(())
    }
}

impl<R: action::Response> TryInto<rrg_proto::GrrMessage> for Response<R> {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError>
    {
        let mut data = Vec::new();
        prost::Message::encode(&self.data.into_proto(), &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: self.response_id,
            request_id: self.request_id,
            r#type: Some(rrg_proto::grr_message::Type::Message.into()),
            args_rdf_name: R::RDF_NAME.map(String::from),
            args: Some(data),
            ..Default::default()
        })
    }
}

struct Status {
    session_id: String,
    request_id: u64,
    result: Result<()>,
}

impl TryInto<rrg_proto::GrrMessage> for Status {

    type Error = prost::EncodeError;

    fn try_into(self)
    -> std::result::Result<rrg_proto::GrrMessage, prost::EncodeError> {
        let status = match self.result {
            Ok(()) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::Ok.into()),
                ..Default::default()
            },
            Err(error) => rrg_proto::GrrStatus {
                status: Some(rrg_proto::grr_status::ReturnedStatus::GenericError.into()),
                error_message: Some(error.to_string()),
                ..Default::default()
            },
        };

        let mut data = Vec::new();
        prost::Message::encode(&status, &mut data)?;

        Ok(rrg_proto::GrrMessage {
            session_id: Some(self.session_id),
            response_id: Some(self.request_id),
            r#type: Some(rrg_proto::grr_message::Type::Status.into()),
            args_rdf_name: Some(String::from("GrrStatus")),
            args: Some(data),
            ..Default::default()
        })
    }
}

fn send(message: rrg_proto::GrrMessage) {
        let packet = Packet {
            service: String::from("GRR"),
            kind: Some(String::from("GrrMessage")),
            data: message,
        };

        if let Err(error) = fleetspeak::send(packet) {
            // If we failed to deliver the message through Fleetspeak, it means
            // that our communication is broken (e.g. the pipe was closed) and
            // the agent should be killed.
            panic!("message delivery failure: {}", error)
        };
}
<|endoftext|>


<commit_before>//! Isometric transformations.

#![allow(missing_doc)]

use std::num::{Zero, One};
use rand::{Rand, Rng};
use structs::mat::{Mat3, Mat4, Mat5};
use traits::structure::{Cast, Dim, Col};
use traits::operations::{Inv, ApproxEq};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
                       Translate, Translation, ToHomogeneous};

use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs};
use structs::rot::{Rot2, Rot3, Rot4};

mod metal;
mod iso_macros;

/// Two dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso2<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot2<N>,
    /// The translation applicable by this isometry.
    translation: Vec2<N>
}

/// Three dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso3<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot3<N>,
    /// The translation applicable by this isometry.
    translation: Vec3<N>
}

/// Four dimensional isometry.
///
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso4<N> {
    /// The rotation applicable by this isometry.
    rotation:    Rot4<N>,
    /// The translation applicable by this isometry.
    translation: Vec4<N>
}

impl<N: Clone + Num + Float> Iso3<N> {
    /// Reorient and translate this transformation such that its local `x` axis points to a given
    /// direction.  Note that the usually known `look_at` function does the same thing but with the
    /// `z` axis. See `look_at_z` for that.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with.
    ///   * up - Vector pointing up. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at(&(*at - *eye), up);
        self.translation = eye.clone();
    }

    /// Reorient and translate this transformation such that its local `z` axis points to a given
    /// direction.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at_z(&(*at - *eye), up);
        self.translation = eye.clone();
    }
}

impl<N> Iso4<N> {
    // XXX remove that when iso_impl works for Iso4
    /// Creates a new isometry from a rotation matrix and a vector.
    #[inline]
    pub fn new_with_rotmat(translation: Vec4<N>, rotation: Rot4<N>) -> Iso4<N> {
        Iso4 {
            rotation:    rotation,
            translation: translation
        }
    }
}

iso_impl!(Iso2, Rot2, Vec2, Vec1)
double_dispatch_binop_decl_trait!(Iso2, Iso2MulRhs)
mul_redispatch_impl!(Iso2, Iso2MulRhs)
rotation_matrix_impl!(Iso2, Rot2, Vec2, Vec1)
rotation_impl!(Iso2, Rot2, Vec1)
dim_impl!(Iso2, 2)
one_impl!(Iso2)
absolute_rotate_impl!(Iso2, Vec2)
rand_impl!(Iso2)
approx_eq_impl!(Iso2)
to_homogeneous_impl!(Iso2, Mat3)
inv_impl!(Iso2)
transform_impl!(Iso2, Vec2)
transformation_impl!(Iso2)
rotate_impl!(Iso2, Vec2)
translation_impl!(Iso2, Vec2)
translate_impl!(Iso2, Vec2)
iso_mul_iso_impl!(Iso2, Iso2MulRhs)
iso_mul_vec_impl!(Iso2, Vec2, Iso2MulRhs)
vec_mul_iso_impl!(Iso2, Vec2, Vec2MulRhs)

iso_impl!(Iso3, Rot3, Vec3, Vec3)
double_dispatch_binop_decl_trait!(Iso3, Iso3MulRhs)
mul_redispatch_impl!(Iso3, Iso3MulRhs)
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3)
rotation_impl!(Iso3, Rot3, Vec3)
dim_impl!(Iso3, 3)
one_impl!(Iso3)
absolute_rotate_impl!(Iso3, Vec3)
rand_impl!(Iso3)
approx_eq_impl!(Iso3)
to_homogeneous_impl!(Iso3, Mat4)
inv_impl!(Iso3)
transform_impl!(Iso3, Vec3)
transformation_impl!(Iso3)
rotate_impl!(Iso3, Vec3)
translation_impl!(Iso3, Vec3)
translate_impl!(Iso3, Vec3)
iso_mul_iso_impl!(Iso3, Iso3MulRhs)
iso_mul_vec_impl!(Iso3, Vec3, Iso3MulRhs)
vec_mul_iso_impl!(Iso3, Vec3, Vec3MulRhs)

// iso_impl!(Iso4, Rot4, Vec4, Vec4)
double_dispatch_binop_decl_trait!(Iso4, Iso4MulRhs)
mul_redispatch_impl!(Iso4, Iso4MulRhs)
// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4)
// rotation_impl!(Iso4, Rot4, Vec4)
dim_impl!(Iso4, 4)
one_impl!(Iso4)
absolute_rotate_impl!(Iso4, Vec4)
// rand_impl!(Iso4)
approx_eq_impl!(Iso4)
to_homogeneous_impl!(Iso4, Mat5)
inv_impl!(Iso4)
transform_impl!(Iso4, Vec4)
transformation_impl!(Iso4)
rotate_impl!(Iso4, Vec4)
translation_impl!(Iso4, Vec4)
translate_impl!(Iso4, Vec4)
iso_mul_iso_impl!(Iso4, Iso4MulRhs)
iso_mul_vec_impl!(Iso4, Vec4, Iso4MulRhs)
vec_mul_iso_impl!(Iso4, Vec4, Vec4MulRhs)
<commit_msg>Make Iso* fields public again.<commit_after>//! Isometric transformations.

#![allow(missing_doc)]

use std::num::{Zero, One};
use rand::{Rand, Rng};
use structs::mat::{Mat3, Mat4, Mat5};
use traits::structure::{Cast, Dim, Col};
use traits::operations::{Inv, ApproxEq};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
                       Translate, Translation, ToHomogeneous};

use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs};
use structs::rot::{Rot2, Rot3, Rot4};

mod metal;
mod iso_macros;

/// Two dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso2<N> {
    /// The rotation applicable by this isometry.
    pub rotation:    Rot2<N>,
    /// The translation applicable by this isometry.
    pub translation: Vec2<N>
}

/// Three dimensional isometry.
///
/// This is the composition of a rotation followed by a translation.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso3<N> {
    /// The rotation applicable by this isometry.
    pub rotation:    Rot3<N>,
    /// The translation applicable by this isometry.
    pub translation: Vec3<N>
}

/// Four dimensional isometry.
///
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[deriving(TotalEq, Eq, Encodable, Decodable, Clone, Show)]
pub struct Iso4<N> {
    /// The rotation applicable by this isometry.
    pub rotation:    Rot4<N>,
    /// The translation applicable by this isometry.
    pub translation: Vec4<N>
}

impl<N: Clone + Num + Float> Iso3<N> {
    /// Reorient and translate this transformation such that its local `x` axis points to a given
    /// direction.  Note that the usually known `look_at` function does the same thing but with the
    /// `z` axis. See `look_at_z` for that.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with.
    ///   * up - Vector pointing up. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at(&(*at - *eye), up);
        self.translation = eye.clone();
    }

    /// Reorient and translate this transformation such that its local `z` axis points to a given
    /// direction.
    ///
    /// # Arguments
    ///   * eye - The new translation of the transformation.
    ///   * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
    ///   aligned with
    ///   * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
    ///   with `at`. Non-colinearity is not checked.
    pub fn look_at_z(&mut self, eye: &Vec3<N>, at: &Vec3<N>, up: &Vec3<N>) {
        self.rotation.look_at_z(&(*at - *eye), up);
        self.translation = eye.clone();
    }
}

impl<N> Iso4<N> {
    // XXX remove that when iso_impl works for Iso4
    /// Creates a new isometry from a rotation matrix and a vector.
    #[inline]
    pub fn new_with_rotmat(translation: Vec4<N>, rotation: Rot4<N>) -> Iso4<N> {
        Iso4 {
            rotation:    rotation,
            translation: translation
        }
    }
}

iso_impl!(Iso2, Rot2, Vec2, Vec1)
double_dispatch_binop_decl_trait!(Iso2, Iso2MulRhs)
mul_redispatch_impl!(Iso2, Iso2MulRhs)
rotation_matrix_impl!(Iso2, Rot2, Vec2, Vec1)
rotation_impl!(Iso2, Rot2, Vec1)
dim_impl!(Iso2, 2)
one_impl!(Iso2)
absolute_rotate_impl!(Iso2, Vec2)
rand_impl!(Iso2)
approx_eq_impl!(Iso2)
to_homogeneous_impl!(Iso2, Mat3)
inv_impl!(Iso2)
transform_impl!(Iso2, Vec2)
transformation_impl!(Iso2)
rotate_impl!(Iso2, Vec2)
translation_impl!(Iso2, Vec2)
translate_impl!(Iso2, Vec2)
iso_mul_iso_impl!(Iso2, Iso2MulRhs)
iso_mul_vec_impl!(Iso2, Vec2, Iso2MulRhs)
vec_mul_iso_impl!(Iso2, Vec2, Vec2MulRhs)

iso_impl!(Iso3, Rot3, Vec3, Vec3)
double_dispatch_binop_decl_trait!(Iso3, Iso3MulRhs)
mul_redispatch_impl!(Iso3, Iso3MulRhs)
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3)
rotation_impl!(Iso3, Rot3, Vec3)
dim_impl!(Iso3, 3)
one_impl!(Iso3)
absolute_rotate_impl!(Iso3, Vec3)
rand_impl!(Iso3)
approx_eq_impl!(Iso3)
to_homogeneous_impl!(Iso3, Mat4)
inv_impl!(Iso3)
transform_impl!(Iso3, Vec3)
transformation_impl!(Iso3)
rotate_impl!(Iso3, Vec3)
translation_impl!(Iso3, Vec3)
translate_impl!(Iso3, Vec3)
iso_mul_iso_impl!(Iso3, Iso3MulRhs)
iso_mul_vec_impl!(Iso3, Vec3, Iso3MulRhs)
vec_mul_iso_impl!(Iso3, Vec3, Vec3MulRhs)

// iso_impl!(Iso4, Rot4, Vec4, Vec4)
double_dispatch_binop_decl_trait!(Iso4, Iso4MulRhs)
mul_redispatch_impl!(Iso4, Iso4MulRhs)
// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4)
// rotation_impl!(Iso4, Rot4, Vec4)
dim_impl!(Iso4, 4)
one_impl!(Iso4)
absolute_rotate_impl!(Iso4, Vec4)
// rand_impl!(Iso4)
approx_eq_impl!(Iso4)
to_homogeneous_impl!(Iso4, Mat5)
inv_impl!(Iso4)
transform_impl!(Iso4, Vec4)
transformation_impl!(Iso4)
rotate_impl!(Iso4, Vec4)
translation_impl!(Iso4, Vec4)
translate_impl!(Iso4, Vec4)
iso_mul_iso_impl!(Iso4, Iso4MulRhs)
iso_mul_vec_impl!(Iso4, Vec4, Iso4MulRhs)
vec_mul_iso_impl!(Iso4, Vec4, Vec4MulRhs)
<|endoftext|>


<commit_before>extern crate getopts;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::io::Write;
use self::getopts::Options;

#[derive(Debug)]
pub struct CommandOptions {
    repo: Option<String>,
    dir: PathBuf,
    args: Vec<String>,
    url: bool,
}

pub enum ParsedArgv {
    Help,
    Version,
    Parsed(CommandOptions),
}

type ErrorMsg = String;

fn normalize_repo_format(mut s: String) -> Result<String, ErrorMsg> {
    if !s.ends_with(".git") {
        s.push_str(".git");
    }

    if s.starts_with("git@") || s.starts_with("https://") || s.starts_with("http://") {
        return Ok(s);
    }

    match s.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}", s)),
        2 => Ok(format!("https://{}", s)),
        _ => Err(format!("Error: Invalid repository format '{}'. Format must be one of 'user/repo', 'service/user/repo' or Git URL.", s)),
    }
}

pub fn parse_options(argv: Vec<String>) -> Result<ParsedArgv, ErrorMsg> {
    let program = argv[0].clone();
    let mut opts = Options::new();

    opts.optflag("h", "help", "Print this help");
    opts.optflag("v", "version", "Show version");
    opts.optflag("u", "url", "Output URL to STDOUT instead of opening in browser");
    opts.optopt("r", "repo", "Shorthand format (user/repo, service/user/repo) or Git URL you want to see", "REPO");
    opts.optopt("d", "dir", "Directory path to your repository", "PATH");

    let matches = opts.parse(&argv[1..]).map_err(|f| format!("{}", f))?;

    if matches.opt_present("h") {
        let brief = format!("Usage: {} [Options] {{Args}}", program);
        errorln!("{}", opts.usage(&brief));
        return Ok(ParsedArgv::Help);
    }

    if matches.opt_present("v") {
        println!("v0.0.0");
        return Ok(ParsedArgv::Version);
    }

    let repo = match matches.opt_str("r") {
        None => None,
        Some(r) => Some(normalize_repo_format(r)?),
    };

    let dir = match matches.opt_str("d") {
        Some(d) => fs::canonicalize(d).map_err(|e| format!("Error on --dir option: {}", e))?,
        None => env::current_dir().map_err(|e| format!("Error on --dir option: {}", e))?,
    };

    Ok(ParsedArgv::Parsed(CommandOptions {
        repo: repo,
        dir: dir,
        url: matches.opt_present("u"),
        args: matches.free,
    }))
}

<commit_msg>get package version via option_env<commit_after>extern crate getopts;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::io::Write;
use self::getopts::Options;

#[derive(Debug)]
pub struct CommandOptions {
    repo: Option<String>,
    dir: PathBuf,
    args: Vec<String>,
    url: bool,
}

pub enum ParsedArgv {
    Help,
    Version,
    Parsed(CommandOptions),
}

type ErrorMsg = String;

fn normalize_repo_format(mut s: String) -> Result<String, ErrorMsg> {
    if !s.ends_with(".git") {
        s.push_str(".git");
    }

    if s.starts_with("git@") || s.starts_with("https://") || s.starts_with("http://") {
        return Ok(s);
    }

    match s.chars().filter(|c| *c == '/').count() {
        1 => Ok(format!("https://github.com/{}", s)),
        2 => Ok(format!("https://{}", s)),
        _ => Err(format!("Error: Invalid repository format '{}'. Format must be one of 'user/repo', 'service/user/repo' or Git URL.", s)),
    }
}

pub fn parse_options(argv: Vec<String>) -> Result<ParsedArgv, ErrorMsg> {
    let program = argv[0].clone();
    let mut opts = Options::new();

    opts.optflag("h", "help", "Print this help");
    opts.optflag("v", "version", "Show version");
    opts.optflag("u", "url", "Output URL to STDOUT instead of opening in browser");
    opts.optopt("r", "repo", "Shorthand format (user/repo, service/user/repo) or Git URL you want to see", "REPO");
    opts.optopt("d", "dir", "Directory path to your repository", "PATH");

    let matches = opts.parse(&argv[1..]).map_err(|f| format!("{}", f))?;

    if matches.opt_present("h") {
        let brief = format!("Usage: {} [Options] {{Args}}", program);
        errorln!("{}", opts.usage(&brief));
        return Ok(ParsedArgv::Help);
    }

    if matches.opt_present("v") {
        println!("{}", option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"));
        return Ok(ParsedArgv::Version);
    }

    let repo = match matches.opt_str("r") {
        None => None,
        Some(r) => Some(normalize_repo_format(r)?),
    };

    let dir = match matches.opt_str("d") {
        Some(d) => fs::canonicalize(d).map_err(|e| format!("Error on --dir option: {}", e))?,
        None => env::current_dir().map_err(|e| format!("Error on --dir option: {}", e))?,
    };

    Ok(ParsedArgv::Parsed(CommandOptions {
        repo: repo,
        dir: dir,
        url: matches.opt_present("u"),
        args: matches.free,
    }))
}

<|endoftext|>


<commit_before>use std::fmt;
use std::borrow::Cow;

use escape::Escaped;

/// An [HTML attribute](https://www.w3.org/TR/html/syntax.html#attributes-0).
///
/// The name for the attribute will not be validated, you must ensure it meets
/// the requirements specified in the spec yourself.
///
/// The value for the attribute will be escaped automatically. If it is an
/// empty string then the attribute will be written with the 'Empty attribute
/// syntax'.
///
/// # Examples
///
/// ```rust
/// let attr = hamlet::attr::Attribute::new("id", "foo");
/// assert_eq!(format!("{}", attr), "id=\"foo\"");
/// ```
///
/// ```rust
/// let attr = hamlet::attr::Attribute::new("id", "bar & baz");
/// assert_eq!(format!("{}", attr), "id=\"bar & baz\"");
/// ```
///
/// ```rust
/// let attr = hamlet::attr::Attribute::new("invalid=id", "foo");
/// assert_eq!(format!("{}", attr), "invalid=id=\"foo\"");
/// ```
///
/// ```rust
/// let attr = hamlet::attr::Attribute::new("checked", "");
/// assert_eq!(format!("{}", attr), "checked");
/// ```
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Attribute<'a> {
    pub name: Cow<'a, str>,
    pub value: Cow<'a, str>,
}

impl<'a> Attribute<'a> {
    /// Create an attribute, useful to avoid having to convert strings to
    /// `Cow<str>` yourself.
    ///
    /// Generally this shouldn't be used directly by end users, it's likely
    /// that there are builder APIs or macros available that make attribute
    /// construction easier, for example the modification methods on
    /// [`AttributeList`](struct.AttributeList.html#methods) or the
    /// [`attrs!`](macro.attrs!.html) macro.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::borrow::Cow;
    /// use hamlet::attr::Attribute;
    ///
    /// let foo = "foo".to_owned();
    /// let foo2 = foo.clone();
    /// assert_eq!(
    ///     Attribute::new("id", foo),
    ///     Attribute {
    ///         name: Cow::Borrowed("id"),
    ///         value: Cow::Owned(foo2),
    ///     });
    /// ```
    pub fn new<N, V>(name: N, value: V) -> Attribute<'a>
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        Attribute {
            name: name.into(),
            value: value.into(),
        }
    }
}

impl<'a> fmt::Display for Attribute<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.value == "" {
            write!(f, "{}", self.name)
        } else {
            write!(f, "{}=\"{}\"", self.name.as_ref(), Escaped(&self.value))
        }
    }
}

#[derive(Clone, Debug, Eq)]
/// A list of [`Attribute`](./struct.Attribute.html)s.
///
/// This is stored as a plain list instead of a set as in most cases it will
/// be a small collection over which a linear search will be more efficient.
pub struct AttributeList<'a>(Cow<'a, [Attribute<'a>]>);

impl<'a> AttributeList<'a> {
    /// Return an empty `AttributeList`
    pub fn empty() -> AttributeList<'a> {
        AttributeList(Cow::Borrowed(&[]))
    }

    /// Note that this does not check for duplicate attribute names. Generally,
    /// end users are not expected to call this method, and instead use
    /// high-level builder APIs or macros available to make construction easier,
    /// such as the provided [`attrs!`](./macro.attrs!.html) macro.
    pub fn from_vec(attrs: Vec<Attribute<'a>>) -> AttributeList<'a> {
        AttributeList(Cow::Owned(attrs))
    }

    /// Pull all attributes out of this collection, useful if you need to
    /// perform some more extensive modification.
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// use hamlet::attr::{ Attribute, AttributeList };
    /// let attrs = attrs!(dataBar = "bar", dataBaz = "baz");
    ///
    /// // Namespace all data attributes for some reason.
    /// let attrs = AttributeList::from_vec(
    ///     attrs.into_vec().into_iter()
    ///         .map(|Attribute { name, value }| {
    ///             Attribute::new(name.replace("data-", "data-foo-"), value)
    ///         })
    ///         .collect());
    ///
    /// assert_eq!(attrs.get("data-foo-bar"), Some("bar"));
    /// # }
    /// ```
    pub fn into_vec(self) -> Vec<Attribute<'a>> {
        self.0.into_owned()
    }

    /// Try and get the value of an attribute.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attrs!(id = "foo");
    /// assert_eq!(attrs.get("id"), Some("foo"));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attrs!(id = "foo");
    /// assert_eq!(attrs.get("class"), None);
    /// # }
    /// ```
    pub fn get<S>(&self, name: S) -> Option<&str>
        where S: AsRef<str>
    {
        self.0.iter().find(|attr| attr.name == name.as_ref()).map(|a| a.value.as_ref())
    }

    /// Unconditionally set an attribute to a value. If the attribute already
    /// exists in the list, update its value, otherwise add a new attribute to
    /// the list.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// attrs.set("id", "bar");
    ///
    /// assert_eq!(attrs.get("id"), Some("bar"));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// attrs.set("class", "bar");
    ///
    /// assert_eq!(attrs.get("class"), Some("bar"));
    /// # }
    /// ```
    pub fn set<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        let (name, value) = (name.into(), value.into());
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name == name) {
            attrs[pos].value = value;
        } else {
            attrs.push(Attribute::new(name, value));
        }
    }

    /// Removes and returns the attribute if there was one.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// assert_eq!(attrs.remove("id").map(|a| a.value).unwrap().as_ref(), "foo");
    /// # }
    /// ```
    pub fn remove<S>(&mut self, name: S) -> Option<Attribute<'a>>
        where S: AsRef<str>
    {
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name.as_ref() == name.as_ref()) {
            Some(attrs.remove(pos))
        } else {
            None
        }
    }

    /// Returns an iterator over the list.
    pub fn iter<'b>(&'b self) -> Iter<'b, 'a> {
        Iter {
            inner: self.0.as_ref(),
            index: 0,
        }
    }
}

/// Immutable [`AttributeList`](./struct.AttributeList.html) iterator.
pub struct Iter<'b, 'a: 'b> {
    inner: &'b [Attribute<'a>],
    index: usize,
}

impl<'a, 'b> Iterator for Iter<'b, 'a> {
    type Item = &'b Attribute<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.index += 1;
        self.inner.get(self.index - 1)
    }
}

impl<'a, 'b> PartialEq<AttributeList<'b>> for AttributeList<'a> {
    fn eq(&self, other: &AttributeList<'b>) -> bool {
        let mut left = self.0.iter().collect::<Vec<_>>();
        let mut right = other.0.iter().collect::<Vec<_>>();
        left.sort();
        right.sort();
        left == right
    }
}
<commit_msg>Add documentation for attribute fields and move examples to them<commit_after>use std::fmt;
use std::borrow::Cow;

use escape::Escaped;

/// An [HTML attribute](https://www.w3.org/TR/html/syntax.html#attributes-0).
///
/// # Examples
///
/// ```rust
/// let attr = hamlet::attr::Attribute::new("id", "foo");
/// assert_eq!(format!("{}", attr), "id=\"foo\"");
/// ```
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Attribute<'a> {
    /// The [attribute's name][name]. The value of this field will not be
    /// validated, you must ensure it meets the requirements specified in the
    /// spec yourself.
    ///
    /// [name]: https://www.w3.org/TR/html/syntax.html#syntax-attribute-name
    ///
    /// # Examples
    ///
    /// ```rust
    /// let attr = hamlet::attr::Attribute::new("invalid=id", "foo");
    /// assert_eq!(format!("{}", attr), "invalid=id=\"foo\"");
    /// ```
    pub name: Cow<'a, str>,

    /// The [attribute's value][value]. This field will be escaped
    /// automatically, if it is an empty string then the attribute will be
    /// written with the 'Empty attribute syntax'.
    ///
    /// [value]: https://www.w3.org/TR/html/syntax.html#syntax-attribute-value
    ///
    /// # Examples
    ///
    /// ```rust
    /// let attr = hamlet::attr::Attribute::new("id", "bar & baz");
    /// assert_eq!(format!("{}", attr), "id=\"bar & baz\"");
    /// ```
    ///
    /// ```rust
    /// let attr = hamlet::attr::Attribute::new("checked", "");
    /// assert_eq!(format!("{}", attr), "checked");
    /// ```
    pub value: Cow<'a, str>,
}

impl<'a> Attribute<'a> {
    /// Create an attribute, useful to avoid having to convert strings to
    /// `Cow<str>` yourself.
    ///
    /// Generally this shouldn't be used directly by end users, it's likely
    /// that there are builder APIs or macros available that make attribute
    /// construction easier, for example the modification methods on
    /// [`AttributeList`](struct.AttributeList.html#methods) or the
    /// [`attrs!`](macro.attrs!.html) macro.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::borrow::Cow;
    /// use hamlet::attr::Attribute;
    ///
    /// let foo = "foo".to_owned();
    /// let foo2 = foo.clone();
    /// assert_eq!(
    ///     Attribute::new("id", foo),
    ///     Attribute {
    ///         name: Cow::Borrowed("id"),
    ///         value: Cow::Owned(foo2),
    ///     });
    /// ```
    pub fn new<N, V>(name: N, value: V) -> Attribute<'a>
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        Attribute {
            name: name.into(),
            value: value.into(),
        }
    }
}

impl<'a> fmt::Display for Attribute<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.value == "" {
            write!(f, "{}", self.name)
        } else {
            write!(f, "{}=\"{}\"", self.name.as_ref(), Escaped(&self.value))
        }
    }
}

#[derive(Clone, Debug, Eq)]
/// A list of [`Attribute`](./struct.Attribute.html)s.
///
/// This is stored as a plain list instead of a set as in most cases it will
/// be a small collection over which a linear search will be more efficient.
pub struct AttributeList<'a>(Cow<'a, [Attribute<'a>]>);

impl<'a> AttributeList<'a> {
    /// Return an empty `AttributeList`
    pub fn empty() -> AttributeList<'a> {
        AttributeList(Cow::Borrowed(&[]))
    }

    /// Note that this does not check for duplicate attribute names. Generally,
    /// end users are not expected to call this method, and instead use
    /// high-level builder APIs or macros available to make construction easier,
    /// such as the provided [`attrs!`](./macro.attrs!.html) macro.
    pub fn from_vec(attrs: Vec<Attribute<'a>>) -> AttributeList<'a> {
        AttributeList(Cow::Owned(attrs))
    }

    /// Pull all attributes out of this collection, useful if you need to
    /// perform some more extensive modification.
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// use hamlet::attr::{ Attribute, AttributeList };
    /// let attrs = attrs!(dataBar = "bar", dataBaz = "baz");
    ///
    /// // Namespace all data attributes for some reason.
    /// let attrs = AttributeList::from_vec(
    ///     attrs.into_vec().into_iter()
    ///         .map(|Attribute { name, value }| {
    ///             Attribute::new(name.replace("data-", "data-foo-"), value)
    ///         })
    ///         .collect());
    ///
    /// assert_eq!(attrs.get("data-foo-bar"), Some("bar"));
    /// # }
    /// ```
    pub fn into_vec(self) -> Vec<Attribute<'a>> {
        self.0.into_owned()
    }

    /// Try and get the value of an attribute.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attrs!(id = "foo");
    /// assert_eq!(attrs.get("id"), Some("foo"));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let attrs = attrs!(id = "foo");
    /// assert_eq!(attrs.get("class"), None);
    /// # }
    /// ```
    pub fn get<S>(&self, name: S) -> Option<&str>
        where S: AsRef<str>
    {
        self.0.iter().find(|attr| attr.name == name.as_ref()).map(|a| a.value.as_ref())
    }

    /// Unconditionally set an attribute to a value. If the attribute already
    /// exists in the list, update its value, otherwise add a new attribute to
    /// the list.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// attrs.set("id", "bar");
    ///
    /// assert_eq!(attrs.get("id"), Some("bar"));
    /// # }
    /// ```
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// attrs.set("class", "bar");
    ///
    /// assert_eq!(attrs.get("class"), Some("bar"));
    /// # }
    /// ```
    pub fn set<N, V>(&mut self, name: N, value: V)
        where N: Into<Cow<'a, str>>,
              V: Into<Cow<'a, str>>
    {
        let (name, value) = (name.into(), value.into());
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name == name) {
            attrs[pos].value = value;
        } else {
            attrs.push(Attribute::new(name, value));
        }
    }

    /// Removes and returns the attribute if there was one.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # #[macro_use] extern crate hamlet;
    /// # fn main() {
    /// let mut attrs = attrs!(id = "foo");
    ///
    /// assert_eq!(attrs.remove("id").map(|a| a.value).unwrap().as_ref(), "foo");
    /// # }
    /// ```
    pub fn remove<S>(&mut self, name: S) -> Option<Attribute<'a>>
        where S: AsRef<str>
    {
        let attrs = self.0.to_mut();

        if let Some(pos) = attrs.iter().position(|attr| attr.name.as_ref() == name.as_ref()) {
            Some(attrs.remove(pos))
        } else {
            None
        }
    }

    /// Returns an iterator over the list.
    pub fn iter<'b>(&'b self) -> Iter<'b, 'a> {
        Iter {
            inner: self.0.as_ref(),
            index: 0,
        }
    }
}

/// Immutable [`AttributeList`](./struct.AttributeList.html) iterator.
pub struct Iter<'b, 'a: 'b> {
    inner: &'b [Attribute<'a>],
    index: usize,
}

impl<'a, 'b> Iterator for Iter<'b, 'a> {
    type Item = &'b Attribute<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.index += 1;
        self.inner.get(self.index - 1)
    }
}

impl<'a, 'b> PartialEq<AttributeList<'b>> for AttributeList<'a> {
    fn eq(&self, other: &AttributeList<'b>) -> bool {
        let mut left = self.0.iter().collect::<Vec<_>>();
        let mut right = other.0.iter().collect::<Vec<_>>();
        left.sort();
        right.sort();
        left == right
    }
}
<|endoftext|>


<commit_before>//! Defines the trait implemented by all textured values

/// Any T which can be copied to return can be computed
/// based on some texture or procedural value.
pub trait Texture<T: Copy> {
    /// Sample the textured value at texture coordinates u,v
    /// at some time. u and v should be in [0, 1]
    fn sample(&self, u: f32, v: f32, time: f32) -> T;
}

/// A single valued, solid 'color' texture for any T
pub struct Solid<T: Copy> {
    val: T,
}
impl<T: Copy> Solid<T> {
    pub fn new(val: T) -> Solid<T> {
        Solid { val: val }
    }
}
impl<T: Copy> Texture<T> for Solid<T> {
    fn sample(&self, _: f32, _: f32, _: f32) -> T {
        self.val
    }
}

<commit_msg>small terminology change Solid -> Constant texture<commit_after>//! Defines the trait implemented by all textured values

/// Any T which can be copied to return can be computed
/// based on some texture or procedural value.
pub trait Texture<T: Copy> {
    /// Sample the textured value at texture coordinates u,v
    /// at some time. u and v should be in [0, 1]
    fn sample(&self, u: f32, v: f32, time: f32) -> T;
}

/// A single valued, solid 'color' texture for any T
pub struct Constant<T: Copy> {
    val: T,
}
impl<T: Copy> Constant<T> {
    pub fn new(val: T) -> Constant<T> {
        Constant { val: val }
    }
}
impl<T: Copy> Texture<T> for Constant<T> {
    fn sample(&self, _: f32, _: f32, _: f32) -> T {
        self.val
    }
}

<|endoftext|>


<commit_before>#[derive(PartialEq)]
pub enum CellStatus {
	Empty,
	Red,
	Blue
}

pub struct Cell {
	pub status: CellStatus
}

impl CellStatus {
	fn to_letter(&self) -> &'static str {
		return match *self {
				CellStatus::Red => "R",
				CellStatus::Blue => "B",
				CellStatus::Empty => "-",
			};
	}
	pub fn to_string(&self) -> &'static str {
		return match *self {
				CellStatus::Red => "Red (Vertically)",
				CellStatus::Blue => "Blue (Horizontally)",
				CellStatus::Empty => "Nothing",
			};
	}
	pub fn get_color_for_player(num: u8) -> CellStatus {
		return match num {
			1 => CellStatus::Red,
			2 => CellStatus::Blue,
			_ => {panic!("This game can't be player with other player than 1 or 2")}
		};
	}
}

impl Cell {
	pub fn new() -> Cell {
		return Cell {
			status: CellStatus::Empty
		};
	}
	pub fn to_string(&self) -> &'static str {
		return self.status.to_letter();
	}
	pub fn is_empty(&self) -> bool {
		match self.status {
			CellStatus::Empty => true,
			_ => false
		}
	}
//	pub fn status_eq(&self, cell_status: CellStatus) -> bool {
//		match self.status {
//			cell_status => true,
//			_ => false
//		}
//	}
}<commit_msg>Red/Blue changed to Black/White for better readability<commit_after>#[derive(PartialEq)]
pub enum CellStatus {
	Empty,
	Black,
	White
}

pub struct Cell {
	pub status: CellStatus
}

impl CellStatus {
	fn to_letter(&self) -> &'static str {
		return match *self {
				CellStatus::Black => "B",
				CellStatus::White => "W",
				CellStatus::Empty => "-",
			};
	}
	pub fn to_string(&self) -> &'static str {
		return match *self {
				CellStatus::Black => "Black (Vertically)",
				CellStatus::White => "White (Horizontally)",
				CellStatus::Empty => "Nothing",
			};
	}
	pub fn get_color_for_player(num: u8) -> CellStatus {
		return match num {
			1 => CellStatus::Black,
			2 => CellStatus::White,
			_ => {panic!("This game can't be player with other player than 1 or 2")}
		};
	}
}

impl Cell {
	pub fn new() -> Cell {
		return Cell {
			status: CellStatus::Empty
		};
	}
	pub fn to_string(&self) -> &'static str {
		return self.status.to_letter();
	}
	pub fn is_empty(&self) -> bool {
		match self.status {
			CellStatus::Empty => true,
			_ => false
		}
	}
}<|endoftext|>