<commit_before>use crate::{
    connection_closer::ConnectionCloser,
    error_handler::ErrorHandler,
    executor::Executor,
    frames::Frames,
    id_sequence::IdSequence,
    internal_rpc::InternalRPCHandle,
    protocol::{AMQPClass, AMQPError, AMQPHardError},
    socket_state::SocketStateHandle,
    BasicProperties, Channel, ChannelState, Configuration, ConnectionState, ConnectionStatus,
    Error, Promise, Result,
};
use amq_protocol::frame::{AMQPFrame, ProtocolVersion};
use log::{debug, error, log_enabled, trace, Level::Trace};
use parking_lot::Mutex;
use std::{collections::HashMap, fmt, sync::Arc};

#[derive(Clone)]
pub(crate) struct Channels {
    inner: Arc<Mutex<Inner>>,
    connection_status: ConnectionStatus,
    internal_rpc: InternalRPCHandle,
    executor: Arc<dyn Executor>,
    frames: Frames,
    error_handler: ErrorHandler,
}

impl Channels {
    pub(crate) fn new(
        configuration: Configuration,
        connection_status: ConnectionStatus,
        waker: SocketStateHandle,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
    ) -> Self {
        Self {
            inner: Arc::new(Mutex::new(Inner::new(configuration, waker))),
            connection_status,
            internal_rpc,
            executor,
            frames,
            error_handler: ErrorHandler::default(),
        }
    }

    pub(crate) fn create(&self, connection_closer: Arc<ConnectionCloser>) -> Result<Channel> {
        self.inner.lock().create(
            self.connection_status.clone(),
            self.internal_rpc.clone(),
            self.frames.clone(),
            self.executor.clone(),
            connection_closer,
        )
    }

    pub(crate) fn create_zero(&self) {
        self.inner
            .lock()
            .create_channel(
                0,
                self.connection_status.clone(),
                self.internal_rpc.clone(),
                self.frames.clone(),
                self.executor.clone(),
                None,
            )
            .set_state(ChannelState::Connected);
    }

    pub(crate) fn get(&self, id: u16) -> Option<Channel> {
        self.inner.lock().channels.get(&id).cloned()
    }

    pub(crate) fn remove(&self, id: u16, error: Error) -> Result<()> {
        self.frames.clear_expected_replies(id, error);
        if self.inner.lock().channels.remove(&id).is_some() {
            Ok(())
        } else {
            Err(Error::InvalidChannel(id))
        }
    }

    pub(crate) fn receive_method(&self, id: u16, method: AMQPClass) -> Result<()> {
        self.get(id)
            .map(|channel| channel.receive_method(method))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        id: u16,
        class_id: u16,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        self.get(id)
            .map(|channel| channel.handle_content_header_frame(class_id, size, properties))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn handle_body_frame(&self, id: u16, payload: Vec<u8>) -> Result<()> {
        self.get(id)
            .map(|channel| channel.handle_body_frame(payload))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn set_connection_closing(&self) {
        self.connection_status.set_state(ConnectionState::Closing);
        for channel in self.inner.lock().channels.values() {
            channel.set_state(ChannelState::Closing);
        }
    }

    pub(crate) fn set_connection_closed(&self, error: Error) -> Result<()> {
        self.connection_status.set_state(ConnectionState::Closed);
        self.inner
            .lock()
            .channels
            .drain()
            .map(|(id, channel)| {
                self.frames.clear_expected_replies(id, error.clone());
                channel.set_state(ChannelState::Closed);
                channel.error_publisher_confirms(error.clone());
                channel.cancel_consumers()
            })
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn set_connection_error(&self, error: Error) -> Result<()> {
        if let ConnectionState::Error = self.connection_status.state() {
            return Ok(());
        }

        error!("Connection error");
        self.connection_status.set_state(ConnectionState::Error);
        self.frames.drop_pending(error.clone());
        self.error_handler.on_error(error.clone());
        self.inner
            .lock()
            .channels
            .drain()
            .map(|(id, channel)| {
                self.frames.clear_expected_replies(id, error.clone());
                channel.set_state(ChannelState::Error);
                channel.error_publisher_confirms(error.clone());
                channel.error_consumers(error.clone())
            })
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner
            .lock()
            .channels
            .values()
            .all(|c| c.status().flow())
    }

    pub(crate) fn send_heartbeat(&self) -> Result<()> {
        debug!("send heartbeat");

        self.get(0)
            .map(|channel0| {
                let (promise, resolver) = Promise::new();

                if log_enabled!(Trace) {
                    promise.set_marker("Heartbeat".into());
                }

                channel0.send_frame(AMQPFrame::Heartbeat(0), resolver, None);
                self.internal_rpc.register_internal_future(promise)
            })
            .unwrap_or_else(|| {
                Err(Error::InvalidConnectionState(
                    self.connection_status.state(),
                ))
            })
    }

    pub(crate) fn handle_frame(&self, f: AMQPFrame) -> Result<()> {
        if let Err(err) = self.do_handle_frame(f) {
            self.set_connection_error(err.clone())?;
            Err(err)
        } else {
            Ok(())
        }
    }

    fn do_handle_frame(&self, f: AMQPFrame) -> Result<()> {
        trace!("will handle frame: {:?}", f);
        match f {
            AMQPFrame::ProtocolHeader(version) => {
                error!(
                    "we asked for AMQP {} but the server only supports AMQP {}",
                    ProtocolVersion::amqp_0_9_1(),
                    version
                );
                let error = Error::InvalidProtocolVersion(version);
                if let Some(resolver) = self.connection_status.connection_resolver() {
                    resolver.swear(Err(error.clone()));
                }
                return Err(error);
            }
            AMQPFrame::Method(channel_id, method) => {
                self.receive_method(channel_id, method)?;
            }
            AMQPFrame::Heartbeat(channel_id) => {
                if channel_id == 0 {
                    debug!("received heartbeat from server");
                } else {
                    error!("received invalid heartbeat on channel {}", channel_id);
                    let error = AMQPError::new(
                        AMQPHardError::FRAMEERROR.into(),
                        format!("heartbeat frame received on channel {}", channel_id).into(),
                    );
                    if let Some(Err(error)) = self.get(0).map(|channel0| {
                        self.internal_rpc
                            .register_internal_future(channel0.connection_close(
                                error.get_id(),
                                error.get_message().as_str(),
                                0,
                                0,
                            ))
                    }) {
                        return Err(error);
                    }
                    return Err(Error::ProtocolError(error));
                }
            }
            AMQPFrame::Header(channel_id, class_id, header) => {
                if channel_id == 0 {
                    error!("received content header on channel {}", channel_id);
                    let error = AMQPError::new(
                        AMQPHardError::CHANNELERROR.into(),
                        format!("content header frame received on channel {}", channel_id).into(),
                    );
                    if let Some(Err(error)) = self.get(0).map(|channel0| {
                        self.internal_rpc
                            .register_internal_future(channel0.connection_close(
                                error.get_id(),
                                error.get_message().as_str(),
                                class_id,
                                0,
                            ))
                    }) {
                        return Err(error);
                    }
                    return Err(Error::ProtocolError(error));
                } else {
                    self.handle_content_header_frame(
                        channel_id,
                        class_id,
                        header.body_size,
                        header.properties,
                    )?;
                }
            }
            AMQPFrame::Body(channel_id, payload) => {
                self.handle_body_frame(channel_id, payload)?;
            }
        }
        Ok(())
    }

    pub(crate) fn set_error_handler<E: FnMut(Error) + Send + 'static>(&self, handler: E) {
        self.error_handler.set_handler(handler);
    }
}

impl fmt::Debug for Channels {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("Channels");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("channels", &inner.channels.values())
                .field("channel_id", &inner.channel_id)
                .field("configuration", &inner.configuration);
        }
        debug
            .field("frames", &self.frames)
            .field("executor", &self.executor)
            .field("connection_status", &self.connection_status)
            .field("error_handler", &self.error_handler)
            .finish()
    }
}

struct Inner {
    channels: HashMap<u16, Channel>,
    channel_id: IdSequence<u16>,
    configuration: Configuration,
    waker: SocketStateHandle,
}

impl Inner {
    fn new(configuration: Configuration, waker: SocketStateHandle) -> Self {
        Self {
            channels: HashMap::default(),
            channel_id: IdSequence::new(false),
            configuration,
            waker,
        }
    }

    fn create_channel(
        &mut self,
        id: u16,
        connection_status: ConnectionStatus,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
        connection_closer: Option<Arc<ConnectionCloser>>,
    ) -> Channel {
        debug!("create channel with id {}", id);
        let channel = Channel::new(
            id,
            self.configuration.clone(),
            connection_status,
            self.waker.clone(),
            internal_rpc,
            frames,
            executor,
            connection_closer,
        );
        self.channels.insert(id, channel.clone_internal());
        channel
    }

    fn create(
        &mut self,
        connection_status: ConnectionStatus,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
        connection_closer: Arc<ConnectionCloser>,
    ) -> Result<Channel> {
        debug!("create channel");
        self.channel_id.set_max(self.configuration.channel_max());
        let first_id = self.channel_id.next();
        let mut id = first_id;
        let mut met_first_id = false;
        loop {
            if id == first_id {
                if met_first_id {
                    break;
                }
                met_first_id = true;
            }
            if !self.channels.contains_key(&id) {
                return Ok(self.create_channel(
                    id,
                    connection_status,
                    internal_rpc,
                    frames,
                    executor,
                    Some(connection_closer),
                ));
            }
            id = self.channel_id.next();
        }
        Err(Error::ChannelsLimitReached)
    }
}
<commit_msg>Add info what happened in connection error<commit_after>use crate::{
    connection_closer::ConnectionCloser,
    error_handler::ErrorHandler,
    executor::Executor,
    frames::Frames,
    id_sequence::IdSequence,
    internal_rpc::InternalRPCHandle,
    protocol::{AMQPClass, AMQPError, AMQPHardError},
    socket_state::SocketStateHandle,
    BasicProperties, Channel, ChannelState, Configuration, ConnectionState, ConnectionStatus,
    Error, Promise, Result,
};
use amq_protocol::frame::{AMQPFrame, ProtocolVersion};
use log::{debug, error, log_enabled, trace, Level::Trace};
use parking_lot::Mutex;
use std::{collections::HashMap, fmt, sync::Arc};

#[derive(Clone)]
pub(crate) struct Channels {
    inner: Arc<Mutex<Inner>>,
    connection_status: ConnectionStatus,
    internal_rpc: InternalRPCHandle,
    executor: Arc<dyn Executor>,
    frames: Frames,
    error_handler: ErrorHandler,
}

impl Channels {
    pub(crate) fn new(
        configuration: Configuration,
        connection_status: ConnectionStatus,
        waker: SocketStateHandle,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
    ) -> Self {
        Self {
            inner: Arc::new(Mutex::new(Inner::new(configuration, waker))),
            connection_status,
            internal_rpc,
            executor,
            frames,
            error_handler: ErrorHandler::default(),
        }
    }

    pub(crate) fn create(&self, connection_closer: Arc<ConnectionCloser>) -> Result<Channel> {
        self.inner.lock().create(
            self.connection_status.clone(),
            self.internal_rpc.clone(),
            self.frames.clone(),
            self.executor.clone(),
            connection_closer,
        )
    }

    pub(crate) fn create_zero(&self) {
        self.inner
            .lock()
            .create_channel(
                0,
                self.connection_status.clone(),
                self.internal_rpc.clone(),
                self.frames.clone(),
                self.executor.clone(),
                None,
            )
            .set_state(ChannelState::Connected);
    }

    pub(crate) fn get(&self, id: u16) -> Option<Channel> {
        self.inner.lock().channels.get(&id).cloned()
    }

    pub(crate) fn remove(&self, id: u16, error: Error) -> Result<()> {
        self.frames.clear_expected_replies(id, error);
        if self.inner.lock().channels.remove(&id).is_some() {
            Ok(())
        } else {
            Err(Error::InvalidChannel(id))
        }
    }

    pub(crate) fn receive_method(&self, id: u16, method: AMQPClass) -> Result<()> {
        self.get(id)
            .map(|channel| channel.receive_method(method))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn handle_content_header_frame(
        &self,
        id: u16,
        class_id: u16,
        size: u64,
        properties: BasicProperties,
    ) -> Result<()> {
        self.get(id)
            .map(|channel| channel.handle_content_header_frame(class_id, size, properties))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn handle_body_frame(&self, id: u16, payload: Vec<u8>) -> Result<()> {
        self.get(id)
            .map(|channel| channel.handle_body_frame(payload))
            .unwrap_or_else(|| Err(Error::InvalidChannel(id)))
    }

    pub(crate) fn set_connection_closing(&self) {
        self.connection_status.set_state(ConnectionState::Closing);
        for channel in self.inner.lock().channels.values() {
            channel.set_state(ChannelState::Closing);
        }
    }

    pub(crate) fn set_connection_closed(&self, error: Error) -> Result<()> {
        self.connection_status.set_state(ConnectionState::Closed);
        self.inner
            .lock()
            .channels
            .drain()
            .map(|(id, channel)| {
                self.frames.clear_expected_replies(id, error.clone());
                channel.set_state(ChannelState::Closed);
                channel.error_publisher_confirms(error.clone());
                channel.cancel_consumers()
            })
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn set_connection_error(&self, error: Error) -> Result<()> {
        if let ConnectionState::Error = self.connection_status.state() {
            return Ok(());
        }

        error!("Connection error: {}", error);
        self.connection_status.set_state(ConnectionState::Error);
        self.frames.drop_pending(error.clone());
        self.error_handler.on_error(error.clone());
        self.inner
            .lock()
            .channels
            .drain()
            .map(|(id, channel)| {
                self.frames.clear_expected_replies(id, error.clone());
                channel.set_state(ChannelState::Error);
                channel.error_publisher_confirms(error.clone());
                channel.error_consumers(error.clone())
            })
            .fold(Ok(()), Result::and)
    }

    pub(crate) fn flow(&self) -> bool {
        self.inner
            .lock()
            .channels
            .values()
            .all(|c| c.status().flow())
    }

    pub(crate) fn send_heartbeat(&self) -> Result<()> {
        debug!("send heartbeat");

        self.get(0)
            .map(|channel0| {
                let (promise, resolver) = Promise::new();

                if log_enabled!(Trace) {
                    promise.set_marker("Heartbeat".into());
                }

                channel0.send_frame(AMQPFrame::Heartbeat(0), resolver, None);
                self.internal_rpc.register_internal_future(promise)
            })
            .unwrap_or_else(|| {
                Err(Error::InvalidConnectionState(
                    self.connection_status.state(),
                ))
            })
    }

    pub(crate) fn handle_frame(&self, f: AMQPFrame) -> Result<()> {
        if let Err(err) = self.do_handle_frame(f) {
            self.set_connection_error(err.clone())?;
            Err(err)
        } else {
            Ok(())
        }
    }

    fn do_handle_frame(&self, f: AMQPFrame) -> Result<()> {
        trace!("will handle frame: {:?}", f);
        match f {
            AMQPFrame::ProtocolHeader(version) => {
                error!(
                    "we asked for AMQP {} but the server only supports AMQP {}",
                    ProtocolVersion::amqp_0_9_1(),
                    version
                );
                let error = Error::InvalidProtocolVersion(version);
                if let Some(resolver) = self.connection_status.connection_resolver() {
                    resolver.swear(Err(error.clone()));
                }
                return Err(error);
            }
            AMQPFrame::Method(channel_id, method) => {
                self.receive_method(channel_id, method)?;
            }
            AMQPFrame::Heartbeat(channel_id) => {
                if channel_id == 0 {
                    debug!("received heartbeat from server");
                } else {
                    error!("received invalid heartbeat on channel {}", channel_id);
                    let error = AMQPError::new(
                        AMQPHardError::FRAMEERROR.into(),
                        format!("heartbeat frame received on channel {}", channel_id).into(),
                    );
                    if let Some(Err(error)) = self.get(0).map(|channel0| {
                        self.internal_rpc
                            .register_internal_future(channel0.connection_close(
                                error.get_id(),
                                error.get_message().as_str(),
                                0,
                                0,
                            ))
                    }) {
                        return Err(error);
                    }
                    return Err(Error::ProtocolError(error));
                }
            }
            AMQPFrame::Header(channel_id, class_id, header) => {
                if channel_id == 0 {
                    error!("received content header on channel {}", channel_id);
                    let error = AMQPError::new(
                        AMQPHardError::CHANNELERROR.into(),
                        format!("content header frame received on channel {}", channel_id).into(),
                    );
                    if let Some(Err(error)) = self.get(0).map(|channel0| {
                        self.internal_rpc
                            .register_internal_future(channel0.connection_close(
                                error.get_id(),
                                error.get_message().as_str(),
                                class_id,
                                0,
                            ))
                    }) {
                        return Err(error);
                    }
                    return Err(Error::ProtocolError(error));
                } else {
                    self.handle_content_header_frame(
                        channel_id,
                        class_id,
                        header.body_size,
                        header.properties,
                    )?;
                }
            }
            AMQPFrame::Body(channel_id, payload) => {
                self.handle_body_frame(channel_id, payload)?;
            }
        }
        Ok(())
    }

    pub(crate) fn set_error_handler<E: FnMut(Error) + Send + 'static>(&self, handler: E) {
        self.error_handler.set_handler(handler);
    }
}

impl fmt::Debug for Channels {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("Channels");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("channels", &inner.channels.values())
                .field("channel_id", &inner.channel_id)
                .field("configuration", &inner.configuration);
        }
        debug
            .field("frames", &self.frames)
            .field("executor", &self.executor)
            .field("connection_status", &self.connection_status)
            .field("error_handler", &self.error_handler)
            .finish()
    }
}

struct Inner {
    channels: HashMap<u16, Channel>,
    channel_id: IdSequence<u16>,
    configuration: Configuration,
    waker: SocketStateHandle,
}

impl Inner {
    fn new(configuration: Configuration, waker: SocketStateHandle) -> Self {
        Self {
            channels: HashMap::default(),
            channel_id: IdSequence::new(false),
            configuration,
            waker,
        }
    }

    fn create_channel(
        &mut self,
        id: u16,
        connection_status: ConnectionStatus,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
        connection_closer: Option<Arc<ConnectionCloser>>,
    ) -> Channel {
        debug!("create channel with id {}", id);
        let channel = Channel::new(
            id,
            self.configuration.clone(),
            connection_status,
            self.waker.clone(),
            internal_rpc,
            frames,
            executor,
            connection_closer,
        );
        self.channels.insert(id, channel.clone_internal());
        channel
    }

    fn create(
        &mut self,
        connection_status: ConnectionStatus,
        internal_rpc: InternalRPCHandle,
        frames: Frames,
        executor: Arc<dyn Executor>,
        connection_closer: Arc<ConnectionCloser>,
    ) -> Result<Channel> {
        debug!("create channel");
        self.channel_id.set_max(self.configuration.channel_max());
        let first_id = self.channel_id.next();
        let mut id = first_id;
        let mut met_first_id = false;
        loop {
            if id == first_id {
                if met_first_id {
                    break;
                }
                met_first_id = true;
            }
            if !self.channels.contains_key(&id) {
                return Ok(self.create_channel(
                    id,
                    connection_status,
                    internal_rpc,
                    frames,
                    executor,
                    Some(connection_closer),
                ));
            }
            id = self.channel_id.next();
        }
        Err(Error::ChannelsLimitReached)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(globs)];
#[feature(macro_rules)];

#[link(name = "benchmark", vers = "alpha", author = "dwrensha")];

#[crate_type = "bin"];

extern mod capnprust;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

mod Uncompressed {
    use capnprust;
    use std;

    pub fn write<T : std::rt::io::Writer>(writer: &mut T,
                                          message: &capnprust::message::MessageBuilder) {
        capnprust::serialize::writeMessage(writer, message);
    }

    pub fn newReader<U : std::rt::io::Reader, T>(
        inputStream : &mut U,
        options : capnprust::message::ReaderOptions,
        cont : &fn(v : &mut capnprust::message::MessageReader) -> T) -> T {
        capnprust::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
}

mod Packed {
    use capnprust;
    use std;

    pub fn write<T : std::rt::io::Writer>(writer: &mut T,
                                          message: &capnprust::message::MessageBuilder) {
        capnprust::serialize_packed::writePackedMessage(writer, message);
    }

    pub fn newReader<U : std::rt::io::Reader, T>(
        inputStream : &mut U,
        options : capnprust::message::ReaderOptions,
        cont : &fn(v : &mut capnprust::message::MessageReader) -> T) -> T {
        capnprust::serialize::InputStreamMessageReader::new(
            &mut capnprust::serialize_packed::PackedInputStream{inner : inputStream},
            options, cont)
    }
}

macro_rules! passByObject(
    ( $testcase:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(&mut rng, request);

                do request.asReader |requestReader| {
                    $testcase::handleRequest(requestReader, response);
                }

                do response.asReader |responseReader| {
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }
            }
        });
    )

macro_rules! passByBytes(
    ( $testcase:ident, $compression:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(&mut rng, request);

                let requestBytes = do std::rt::io::mem::with_mem_writer |writer| {
                    $compression::write(writer, messageReq)
                };

                do $compression::newReader(
                      &mut std::rt::io::mem::BufReader::new(requestBytes),
                      capnprust::message::DEFAULT_READER_OPTIONS) |requestReader| {
                    let requestReader = $testcase::newRequestReader(requestReader.getRoot());
                    $testcase::handleRequest(requestReader, response);
                }

                let responseBytes = do std::rt::io::mem::with_mem_writer |writer| {
                    $compression::write(writer, messageRes);
                };

                do $compression::newReader(
                    &mut std::rt::io::mem::BufReader::new(responseBytes),
                    capnprust::message::DEFAULT_READER_OPTIONS) |responseReader| {
                    let responseReader = $testcase::newResponseReader(responseReader.getRoot());
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }
            }
        });
    )

macro_rules! server(
    ( $testcase:ident, $iters:expr) => ({
            fail!("unimplemented")
        });
    )

macro_rules! syncClient(
    ( $testcase:ident, $iters:expr) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let _response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let _expected = $testcase::setupRequest(&mut rng, request);
                fail!("unimplemented");
            }
        });
    )

macro_rules! passByPipe(
    ( $testcase:ident, $iters:expr) => ({
            fail!("unimplemented");
        });
    )

macro_rules! doTestcase(
    ( $testcase:ident, $mode:expr, $reuse:expr, $compression:ident, $iters:expr ) => ({
            match $mode {
                ~"object" => passByObject!($testcase, $iters),
                ~"bytes" => passByBytes!($testcase, $compression, $iters),
                ~"server" => server!($testcase, $iters),
                ~"client" => syncClient!($testcase, $iters),
                s => fail!("unrecognized mode: {}", s)
            }
        });
    )

macro_rules! doTestcase1(
    ( $testcase:expr, $mode:expr, $reuse:expr, $compression:ident, $iters:expr) => ({
            match $testcase {
                ~"carsales" => doTestcase!(carsales, $mode, $reuse, $compression, $iters),
                ~"catrank" => doTestcase!(catrank, $mode, $reuse, $compression, $iters),
                ~"eval" => doTestcase!(eval, $mode, $reuse, $compression, $iters),
                s => fail!("unrecognized test case: {}", s)
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 6) {
        println!("USAGE: {} CASE MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        return;
    }

    let iters = match from_str::<u64>(args[5]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[5]);
            return;
        }
    };

    match args[4] {
        ~"none" => doTestcase1!(args[1], args[2],  args[3], Uncompressed, iters),
        ~"packed" => doTestcase1!(args[1], args[2], args[3], Packed, iters),
        s => fail!("unrecognized compression: {}", s)
    }

}
<commit_msg>getting starting on passByPipe<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

#[feature(globs)];
#[feature(macro_rules)];

#[link(name = "benchmark", vers = "alpha", author = "dwrensha")];

#[crate_type = "bin"];

extern mod capnprust;

pub mod common;

pub mod carsales_capnp;
pub mod carsales;

pub mod catrank_capnp;
pub mod catrank;

pub mod eval_capnp;
pub mod eval;

mod Uncompressed {
    use capnprust;
    use std;

    pub fn write<T : std::rt::io::Writer>(writer: &mut T,
                                          message: &capnprust::message::MessageBuilder) {
        capnprust::serialize::writeMessage(writer, message);
    }

    pub fn newReader<U : std::rt::io::Reader, T>(
        inputStream : &mut U,
        options : capnprust::message::ReaderOptions,
        cont : &fn(v : &mut capnprust::message::MessageReader) -> T) -> T {
        capnprust::serialize::InputStreamMessageReader::new(inputStream, options, cont)
    }
}

mod Packed {
    use capnprust;
    use std;

    pub fn write<T : std::rt::io::Writer>(writer: &mut T,
                                          message: &capnprust::message::MessageBuilder) {
        capnprust::serialize_packed::writePackedMessage(writer, message);
    }

    pub fn newReader<U : std::rt::io::Reader, T>(
        inputStream : &mut U,
        options : capnprust::message::ReaderOptions,
        cont : &fn(v : &mut capnprust::message::MessageReader) -> T) -> T {
        capnprust::serialize::InputStreamMessageReader::new(
            &mut capnprust::serialize_packed::PackedInputStream{inner : inputStream},
            options, cont)
    }
}

macro_rules! passByObject(
    ( $testcase:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(&mut rng, request);

                do request.asReader |requestReader| {
                    $testcase::handleRequest(requestReader, response);
                }

                do response.asReader |responseReader| {
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }
            }
        });
    )

macro_rules! passByBytes(
    ( $testcase:ident, $compression:ident, $iters:expr ) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let expected = $testcase::setupRequest(&mut rng, request);

                let requestBytes = do std::rt::io::mem::with_mem_writer |writer| {
                    $compression::write(writer, messageReq)
                };

                do $compression::newReader(
                      &mut std::rt::io::mem::BufReader::new(requestBytes),
                      capnprust::message::DEFAULT_READER_OPTIONS) |requestReader| {
                    let requestReader = $testcase::newRequestReader(requestReader.getRoot());
                    $testcase::handleRequest(requestReader, response);
                }

                let responseBytes = do std::rt::io::mem::with_mem_writer |writer| {
                    $compression::write(writer, messageRes);
                };

                do $compression::newReader(
                    &mut std::rt::io::mem::BufReader::new(responseBytes),
                    capnprust::message::DEFAULT_READER_OPTIONS) |responseReader| {
                    let responseReader = $testcase::newResponseReader(responseReader.getRoot());
                    if (! $testcase::checkResponse(responseReader, expected)) {
                        println("Incorrect response.");
                    }
                }
            }
        });
    )

macro_rules! server(
    ( $testcase:ident, $iters:expr) => ({
            fail!("unimplemented")
        });
    )

macro_rules! syncClient(
    ( $testcase:ident, $iters:expr) => ({
            let mut rng = common::FastRand::new();
            for _ in range(0, $iters) {
                let mut messageReq = capnprust::message::MessageBuilder::new_default();
                let mut messageRes = capnprust::message::MessageBuilder::new_default();

                let request = messageReq.initRoot::<$testcase::RequestBuilder>();
                let _response = messageRes.initRoot::<$testcase::ResponseBuilder>();
                let _expected = $testcase::setupRequest(&mut rng, request);
                fail!("unimplemented");
            }
        });
    )

macro_rules! passByPipe(
    ( $testcase:ident, $compression:ident, $iters:expr) => ({
            use std::rt::io::process;

            // get a rustc crash if we put this in line below
            let io = ~[process::CreatePipe(true, false), // stdin
                       process::CreatePipe(false, true), // stdout
                       process::Ignored];

            let config = process::ProcessConfig {
                program: "./benchmark/benchmark",
                args: [],
                env : None,
                cwd: None,
                io : io
            };
            match process::Process::new(config) {
                Some(ref mut p) => {
                    println!("{:?}", p);
                    let s = p.io[1].read_to_end();
                    std::rt::io::stdout().write(s);
                    println!("{}", p.wait());
                }
                None => {
                    println("bummer");
                }
            }
        });
    )

macro_rules! doTestcase(
    ( $testcase:ident, $mode:expr, $reuse:expr, $compression:ident, $iters:expr ) => ({
            match $mode {
                ~"object" => passByObject!($testcase, $iters),
                ~"bytes" => passByBytes!($testcase, $compression, $iters),
                ~"server" => server!($testcase, $iters),
                ~"client" => syncClient!($testcase, $iters),
                ~"pipe" => passByPipe!($testcase, $compression, $iters),
                s => fail!("unrecognized mode: {}", s)
            }
        });
    )

macro_rules! doTestcase1(
    ( $testcase:expr, $mode:expr, $reuse:expr, $compression:ident, $iters:expr) => ({
            match $testcase {
                ~"carsales" => doTestcase!(carsales, $mode, $reuse, $compression, $iters),
                ~"catrank" => doTestcase!(catrank, $mode, $reuse, $compression, $iters),
                ~"eval" => doTestcase!(eval, $mode, $reuse, $compression, $iters),
                s => fail!("unrecognized test case: {}", s)
            }
        });
    )

pub fn main () {

    let args = std::os::args();

    if (args.len() != 6) {
        println!("USAGE: {} CASE MODE REUSE COMPRESSION ITERATION_COUNT", args[0]);
        std::os::set_exit_status(1);
        return;
    }

    let iters = match from_str::<u64>(args[5]) {
        Some (n) => n,
        None => {
            println!("Could not parse a u64 from: {}", args[5]);
            std::os::set_exit_status(1);
            return;
        }
    };

    match args[4] {
        ~"none" => doTestcase1!(args[1], args[2],  args[3], Uncompressed, iters),
        ~"packed" => doTestcase1!(args[1], args[2], args[3], Packed, iters),
        s => fail!("unrecognized compression: {}", s)
    }

}
<|endoftext|>


<commit_before>use std::old_io::IoError;
use std::old_io::IoErrorKind;
use std::old_io::Command;
use std::old_io::process::ProcessOutput;

// Scope of command line argument.
#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum Scope {
	// Preprocessing argument
	Preprocessor,
	// Compiler argument
	Compiler,
	// Preprocessor & compiler argument
	Shared,
	// Unknown argument - local build only
	Ignore,
}

#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum InputKind {
	Source,
	Marker,
	Precompiled,
}

#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum OutputKind {
	Object,
	Marker,
}

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Arg {
	Flag{scope:Scope, flag: String},
	Param{scope:Scope, flag: String, value: String},
	Input{kind:InputKind, flag: String, file: String},
	Output{kind:OutputKind, flag: String, file: String}
}

pub struct CompilationTask {
	// Original compiler executable.
	pub command: Command,
	// Parsed arguments.
	pub args: Vec<Arg>,
	// Source language.
	pub language: String,
	// Input source file name.
	pub input_source: Path,
	// Input precompiled header file name.
	pub input_precompiled: Option<Path>,
	// Output object file name.
	pub output_object: Path,
	// Output precompiled header file name.
	pub output_precompiled: Option<Path>,
	// Marker for precompiled header.
	pub marker_precompiled: Option<String>,
}

pub struct PreprocessResult {
	// Hash
	pub hash: String,
	// Preprocessed file
	pub content: Vec<u8>,
}

pub trait Compiler {
	// Parse compiler arguments.
	fn create_task(&self, command: &Command, args: &[String]) -> Result<CompilationTask, String>;

	// Preprocessing source file.
	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, IoError>;

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessResult) -> Result<ProcessOutput, IoError>;

	// Run preprocess and compile.
	fn try_compile(&self, command: &Command, args: &[String]) -> Result<ProcessOutput, IoError> {
		match self.create_task(command, args) {
			Ok(task) => self.compile_step(&task, try! (self.preprocess_step(&task))),
			Err(e) => Err(IoError {
				kind: IoErrorKind::InvalidInput,
				desc: "Can't parse command line arguments",
				detail: Some(e)
			})
		}
	}

	// Run preprocess and compile.
	fn compile(&self, command: &Command, args: &[String]) -> Result<ProcessOutput, IoError> {
		match self.try_compile(command, args) {
			Ok(output) => Ok(output),
			// todo: log error reason
			Err(_) => command.clone().args(args).output()
		}
	}
}
<commit_msg>Print command line parsing error to console<commit_after>use std::old_io::IoError;
use std::old_io::IoErrorKind;
use std::old_io::Command;
use std::old_io::process::ProcessOutput;

// Scope of command line argument.
#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum Scope {
	// Preprocessing argument
	Preprocessor,
	// Compiler argument
	Compiler,
	// Preprocessor & compiler argument
	Shared,
	// Unknown argument - local build only
	Ignore,
}

#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum InputKind {
	Source,
	Marker,
	Precompiled,
}

#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
pub enum OutputKind {
	Object,
	Marker,
}

#[derive(Debug)]
#[derive(PartialEq)]
pub enum Arg {
	Flag{scope:Scope, flag: String},
	Param{scope:Scope, flag: String, value: String},
	Input{kind:InputKind, flag: String, file: String},
	Output{kind:OutputKind, flag: String, file: String}
}

pub struct CompilationTask {
	// Original compiler executable.
	pub command: Command,
	// Parsed arguments.
	pub args: Vec<Arg>,
	// Source language.
	pub language: String,
	// Input source file name.
	pub input_source: Path,
	// Input precompiled header file name.
	pub input_precompiled: Option<Path>,
	// Output object file name.
	pub output_object: Path,
	// Output precompiled header file name.
	pub output_precompiled: Option<Path>,
	// Marker for precompiled header.
	pub marker_precompiled: Option<String>,
}

pub struct PreprocessResult {
	// Hash
	pub hash: String,
	// Preprocessed file
	pub content: Vec<u8>,
}

pub trait Compiler {
	// Parse compiler arguments.
	fn create_task(&self, command: &Command, args: &[String]) -> Result<CompilationTask, String>;

	// Preprocessing source file.
	fn preprocess_step(&self, task: &CompilationTask) -> Result<PreprocessResult, IoError>;

	// Compile preprocessed file.
	fn compile_step(&self, task: &CompilationTask, preprocessed: PreprocessResult) -> Result<ProcessOutput, IoError>;

	// Run preprocess and compile.
	fn try_compile(&self, command: &Command, args: &[String]) -> Result<ProcessOutput, IoError> {
		match self.create_task(command, args) {
			Ok(task) => self.compile_step(&task, try! (self.preprocess_step(&task))),
			Err(e) => Err(IoError {
				kind: IoErrorKind::InvalidInput,
				desc: "Can't parse command line arguments",
				detail: Some(e)
			})
		}
	}

	// Run preprocess and compile.
	fn compile(&self, command: &Command, args: &[String]) -> Result<ProcessOutput, IoError> {
		match self.try_compile(command, args) {
			Ok(output) => Ok(output),
			// todo: log error reason
			Err(e) => {
				println! ("Can't use octobuild for compiling file, use failback compilation: {:?}", e);
				command.clone().args(args).output()
			}
		}
	}
}
<|endoftext|>


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

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules, managed_boxes)];

#[link(name = "ears",
       vers = "0.1",
       package_id = "github.com/JeremyLetang/ears",
       author = "letang.jeremy@gmail.com",
       uuid = "D0271EC6-5F27-4C72-BBEA-1341DC665F34",
       url = "https://github.com/JeremyLetang/ears")];

#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];
// #[warn(missing_doc)];
#[allow(dead_code)];

extern mod extra;

// Reexport public API
pub use init::ears_init;
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<commit_msg>remove link attribute<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
# ears

__ears__ is a simple library for play Audio in Rust.

__ears__ is build on the top of OpenAL and libsndfile.

* Provide an acces to the OpenAL spatialization functionnality in a simple way.
* Accept a lot of audio format thanks to libsndfile.

# A simple example

```Rust
extern mod ears;
use ears::Sound;

fn main() -> {
	// Create a new Sound.
	let snd = Sound::new(~"path/to/my/sound.ogg").unwrap();

	// Play the Sound
	snd.play();

	// Wait until the end of the sound
	while snd.is_playing() {}
}
```

# Functionnality

__ears__ provide two way for play audio files.

* The Sound class, which represent light sounds who can share a buffer of samples with another Sound.
* The Music class, which is a bigger sound and who can't share sample buffer.

# Use ears

As said before, __ears__ require OpenAL and libsndfile, you need to install these two libraries in your system.

__ears__ compile against the last Rust compiler, so if it doesn't work on your computer you may need to update your compiler.

__ears__ work fully with `rustpkg`, so just install __ears__ in your project workspace like this :

```Shell
> rustpkg install github.com/JeremyLetang/ears
```

then import stuff from __ears__ in your project, you can import all the stuff :

```Rust
extern mod ears;

use ears::*;
```

or a specific :

```Rust
extern mod ears;

use ears::Music;
```

# Compile examples

Like __ears__ you can build the examples with `rustpkg`, just do :

```Shell
> rustpkg install examples/an_example
```
*/

#[feature(globs, macro_rules, managed_boxes)];

#[crate_id = "ears#0.1"]
#[desc = "Easy Api in Rust for Sounds"];
#[license = "MIT"];
#[crate_type = "lib"];
// #[warn(missing_doc)];
#[allow(dead_code)];

extern mod extra;

// Reexport public API
pub use init::ears_init;
pub use music::Music;
pub use sound::Sound;
pub use states::{State, Initial, Playing, Paused, Stopped};
pub use sound_data::SoundData;
pub use audio_controller::AudioController;
pub use audio_tags::{AudioTags, Tags};

// Hidden internal bindings
#[doc(hidden)]
pub mod internal;
#[doc(hidden)]
mod openal;
#[doc(hidden)]
mod sndfile;

// The public ears API
pub mod init;
pub mod listener;
pub mod sound;
pub mod music;
pub mod sound_data;
pub mod states;
pub mod audio_controller;
pub mod audio_tags;
pub mod recorder;
<|endoftext|>


<commit_before>//! The elements of an Openstreetmap XML file.
//!
//! For now, the types only cotain a limited set of the most important
//! attributes.

use std::{borrow, hash, str};
use std::collections::{HashMap, HashSet};

//------------ Osm ----------------------------------------------------------

/// An OSM data set.
///
/// Contains a set each for nodes, ways, and relations.
pub struct Osm {
    nodes: HashSet<Node>,
    ways: HashSet<Way>,
    relations: HashSet<Relation>,
}

impl Osm {
    pub fn new() -> Self {
        Osm {
            nodes: HashSet::new(),
            ways: HashSet::new(),
            relations: HashSet::new(),
        }
    }

    pub fn add_node(&mut self, node: Node) -> bool {
        self.nodes.insert(node)
    }

    pub fn add_way(&mut self, way: Way) -> bool {
        self.ways.insert(way)
    }

    pub fn add_relation(&mut self, rel: Relation) -> bool {
        self.relations.insert(rel)
    }
}

impl Osm {
    pub fn nodes(&self) -> &HashSet<Node> {
        &self.nodes
    }

    pub fn has_node(&self, id: i64) -> bool {
        self.nodes.contains(&id)
    }

    pub fn get_node(&self, id: i64) -> Option<&Node> {
        self.nodes.get(&id)
    }

    pub fn ways(&self) -> &HashSet<Way> {
        &self.ways
    }

    pub fn has_way(&self, id: i64) -> bool {
        self.ways.contains(&id)
    }

    pub fn get_way(&self, id: i64) -> Option<&Way> {
        self.ways.get(&id)
    }

    pub fn relations(&self) -> &HashSet<Relation> {
        &self.relations
    }

    pub fn has_relation(&self, id: i64) -> bool {
        self.relations.contains(&id)
    }

    pub fn get_relation(&self, id: i64) -> Option<&Relation> {
        self.relations.get(&id)
    }
}

//------------ Node ---------------------------------------------------------

pub struct Node {
    id: i64,
    lat: f64,
    lon: f64,
    tags: Tags,
}

impl Node {
    pub fn new(id: i64, lat: f64, lon: f64) -> Self {
        Node {
            id: id,
            lat: lat,
            lon: lon,
            tags: Tags::new()
        }
    }

    pub fn set_lat(&mut self, lat: f64) {
        self.lat = lat
    }

    pub fn set_lon(&mut self, lon: f64) {
        self.lon = lon
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Node {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn lat(&self) -> f64 {
        self.lat
    }

    pub fn lon(&self) -> f64 {
        self.lon
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Node {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Node { }

impl hash::Hash for Node {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Way ----------------------------------------------------------

pub struct Way {
    id: i64,
    nodes: Vec<i64>,
    tags: Tags,
}

impl Way {
    pub fn new(id: i64) -> Self {
        Way {
            id: id,
            nodes: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_node(&mut self, id: i64) {
        self.nodes.push(id)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Way {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn nodes(&self) -> &[i64] {
        &self.nodes
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Way {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Way {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Way { }

impl hash::Hash for Way {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Relation ------------------------------------------------------

pub struct Relation {
    id: i64,
    members: Vec<Member>,
    tags: Tags,
}

impl Relation {
    pub fn new(id: i64) -> Self {
        Relation {
            id: id,
            members: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_member(&mut self, member: Member) {
        self.members.push(member)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value)
    }
}

impl Relation {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn members(&self) -> &[Member] {
        &self.members
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Relation {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Relation {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Relation { }

impl hash::Hash for Relation {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Member --------------------------------------------------------

pub struct Member {
    mtype: MemberType,
    id: i64,
    role: String
}

impl Member {
    pub fn new(mtype: MemberType, id: i64, role: String) -> Self {
        Member {
            mtype: mtype,
            id: id,
            role: role
        }
    }
}

impl Member {
    pub fn mtype(&self) -> MemberType {
        self.mtype
    }

    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn role(&self) -> &str {
        &self.role
    }
}

//------------ MemberType ----------------------------------------------------

#[derive(Clone, Copy, Debug)]
pub enum MemberType {
    Way,
    Node,
    Relation
}

impl str::FromStr for MemberType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "way" => Ok(MemberType::Way),
            "node" => Ok(MemberType::Node),
            "relation" => Ok(MemberType::Relation),
            _ => Err(format!("invalid member type '{}'", s))
        }
    }
}

//------------ Tags ----------------------------------------------------------

pub struct Tags(HashMap<String, String>);

impl Tags {
    pub fn new() -> Self {
        Tags(HashMap::new())
    }

    pub fn insert(&mut self, key: String, value: String) {
        self.0.insert(key, value);
    }

    pub fn remove(&mut self, key: &str) -> Option<String> {
        self.0.remove(key)
    }
}

impl Tags {
    pub fn has(&self, key: &str) -> bool {
        self.0.contains_key(key)
    }

    pub fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).map(AsRef::as_ref)
    }
}

<commit_msg>Mutable access to relations and their tags.<commit_after>//! The elements of an Openstreetmap XML file.
//!
//! For now, the types only cotain a limited set of the most important
//! attributes.

use std::{borrow, hash, str};
use std::collections::{HashMap, HashSet};

//------------ Osm ----------------------------------------------------------

/// An OSM data set.
///
/// Contains a set each for nodes, ways, and relations.
pub struct Osm {
    nodes: HashSet<Node>,
    ways: HashSet<Way>,
    relations: HashSet<Relation>,
}

impl Osm {
    pub fn new() -> Self {
        Osm {
            nodes: HashSet::new(),
            ways: HashSet::new(),
            relations: HashSet::new(),
        }
    }

    pub fn add_node(&mut self, node: Node) -> bool {
        self.nodes.insert(node)
    }

    pub fn add_way(&mut self, way: Way) -> bool {
        self.ways.insert(way)
    }

    pub fn add_relation(&mut self, rel: Relation) -> bool {
        self.relations.insert(rel)
    }
}

impl Osm {
    pub fn nodes(&self) -> &HashSet<Node> {
        &self.nodes
    }

    pub fn has_node(&self, id: i64) -> bool {
        self.nodes.contains(&id)
    }

    pub fn get_node(&self, id: i64) -> Option<&Node> {
        self.nodes.get(&id)
    }

    pub fn ways(&self) -> &HashSet<Way> {
        &self.ways
    }

    pub fn has_way(&self, id: i64) -> bool {
        self.ways.contains(&id)
    }

    pub fn get_way(&self, id: i64) -> Option<&Way> {
        self.ways.get(&id)
    }

    pub fn relations(&self) -> &HashSet<Relation> {
        &self.relations
    }

    pub fn relations_mut(&mut self) -> &mut HashSet<Relation> {
        &mut self.relations
    }

    pub fn has_relation(&self, id: i64) -> bool {
        self.relations.contains(&id)
    }

    pub fn get_relation(&self, id: i64) -> Option<&Relation> {
        self.relations.get(&id)
    }
}

//------------ Node ---------------------------------------------------------

pub struct Node {
    id: i64,
    lat: f64,
    lon: f64,
    tags: Tags,
}

impl Node {
    pub fn new(id: i64, lat: f64, lon: f64) -> Self {
        Node {
            id: id,
            lat: lat,
            lon: lon,
            tags: Tags::new()
        }
    }

    pub fn set_lat(&mut self, lat: f64) {
        self.lat = lat
    }

    pub fn set_lon(&mut self, lon: f64) {
        self.lon = lon
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Node {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn lat(&self) -> f64 {
        self.lat
    }

    pub fn lon(&self) -> f64 {
        self.lon
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Node {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Node {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Node { }

impl hash::Hash for Node {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Way ----------------------------------------------------------

pub struct Way {
    id: i64,
    nodes: Vec<i64>,
    tags: Tags,
}

impl Way {
    pub fn new(id: i64) -> Self {
        Way {
            id: id,
            nodes: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_node(&mut self, id: i64) {
        self.nodes.push(id)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value);
    }
}

impl Way {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn nodes(&self) -> &[i64] {
        &self.nodes
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }
}

impl borrow::Borrow<i64> for Way {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Way {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Way { }

impl hash::Hash for Way {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Relation ------------------------------------------------------

pub struct Relation {
    id: i64,
    members: Vec<Member>,
    tags: Tags,
}

impl Relation {
    pub fn new(id: i64) -> Self {
        Relation {
            id: id,
            members: Vec::new(),
            tags: Tags::new(),
        }
    }

    pub fn push_member(&mut self, member: Member) {
        self.members.push(member)
    }

    pub fn insert_tag(&mut self, key: String, value: String) {
        self.tags.insert(key, value)
    }
}

impl Relation {
    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn members(&self) -> &[Member] {
        &self.members
    }

    pub fn tags(&self) -> &Tags {
        &self.tags
    }

    pub fn tags_mut(&mut self) ->&mut Tags {
        &mut self.tags
    }
}

impl borrow::Borrow<i64> for Relation {
    fn borrow(&self) -> &i64 {
        &self.id
    }
}

impl PartialEq for Relation {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id
    }
}

impl Eq for Relation { }

impl hash::Hash for Relation {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.id.hash(state)
    }
}

//------------ Member --------------------------------------------------------

pub struct Member {
    mtype: MemberType,
    id: i64,
    role: String
}

impl Member {
    pub fn new(mtype: MemberType, id: i64, role: String) -> Self {
        Member {
            mtype: mtype,
            id: id,
            role: role
        }
    }
}

impl Member {
    pub fn mtype(&self) -> MemberType {
        self.mtype
    }

    pub fn id(&self) -> i64 {
        self.id
    }

    pub fn role(&self) -> &str {
        &self.role
    }
}

//------------ MemberType ----------------------------------------------------

#[derive(Clone, Copy, Debug)]
pub enum MemberType {
    Way,
    Node,
    Relation
}

impl str::FromStr for MemberType {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "way" => Ok(MemberType::Way),
            "node" => Ok(MemberType::Node),
            "relation" => Ok(MemberType::Relation),
            _ => Err(format!("invalid member type '{}'", s))
        }
    }
}

//------------ Tags ----------------------------------------------------------

pub struct Tags(HashMap<String, String>);

impl Tags {
    pub fn new() -> Self {
        Tags(HashMap::new())
    }

    pub fn insert(&mut self, key: String, value: String) {
        self.0.insert(key, value);
    }

    pub fn remove(&mut self, key: &str) -> Option<String> {
        self.0.remove(key)
    }
}

impl Tags {
    pub fn has(&self, key: &str) -> bool {
        self.0.contains_key(key)
    }

    pub fn get(&self, key: &str) -> Option<&str> {
        self.0.get(key).map(AsRef::as_ref)
    }
}

<|endoftext|>


<commit_before>use std::{error,fmt};
use std::num::Float;

use super::{EvaluationContext,Functions,Value};

pub trait Function {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>;
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum ArgumentType {
    Nodeset,
    Boolean,
    Number,
    String,
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum Error {
    TooManyArguments{ expected: usize, actual: usize },
    NotEnoughArguments{ expected: usize, actual: usize },
    WrongType{ expected: ArgumentType, actual: ArgumentType },
}

impl Error {
    fn wrong_type(actual: &Value, expected: ArgumentType) -> Error {
        let actual = match *actual {
            Value::Nodes(..)   => ArgumentType::Nodeset,
            Value::String(..)  => ArgumentType::String,
            Value::Number(..)  => ArgumentType::Number,
            Value::Boolean(..) => ArgumentType::Boolean,
        };

        Error::WrongType {
            expected: expected,
            actual: actual
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            TooManyArguments{..}   => "too many arguments",
            NotEnoughArguments{..} => "not enough arguments",
            WrongType{..}          => "argument of wrong type",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            TooManyArguments{expected, actual} => {
                write!(fmt, "too many arguments, expected {} but had {}", expected, actual)
            },
            NotEnoughArguments{expected, actual} => {
                write!(fmt, "not enough arguments, expected {} but had {}", expected, actual)
            },
            WrongType{expected, actual} => {
                write!(fmt, "argument was the wrong type, expected {:?} but had {:?}", expected, actual)
            },
        }
    }
}

fn minimum_arg_count<T>(args: &Vec<T>, minimum: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < minimum {
        Err(Error::NotEnoughArguments{expected: minimum, actual: actual})
    } else {
        Ok(())
    }
}

fn exact_arg_count<T>(args: &Vec<T>, expected: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < expected {
        Err(Error::NotEnoughArguments{ expected: expected, actual: actual })
    } else if actual > expected {
        Err(Error::TooManyArguments{ expected: expected, actual: actual })
    } else {
        Ok(())
    }
}

fn string_args(args: Vec<Value>) -> Result<Vec<String>, Error> {
    fn string_arg(v: Value) -> Result<String, Error> {
        match v {
            Value::String(s) => Ok(s),
            _ => Err(Error::wrong_type(&v, ArgumentType::String)),
        }
    }

    args.into_iter().map(string_arg).collect()
}

fn one_number(args: Vec<Value>) -> Result<f64, Error> {
    match &args[0] {
        &Value::Number(v) => Ok(v),
        a => Err(Error::wrong_type(a, ArgumentType::Number)),
    }
}

struct Last;

impl Function for Last {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.size() as f64))
    }
}

struct Position;

impl Function for Position {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.position() as f64))
    }
}

struct Count;

impl Function for Count {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Nodes(ref nodeset) => Ok(Value::Number(nodeset.size() as f64)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Nodeset)),
        }
    }
}

struct Concat;

impl Function for Concat {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(minimum_arg_count(&args, 2));
        let args = try!(string_args(args));
        Ok(Value::String(args.concat()))
    }
}

struct TwoStringPredicate(fn(&str, &str) -> bool);

impl Function for TwoStringPredicate {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = self.0(&*args[0], &*args[1]);
        Ok(Value::Boolean(v))
    }
}

fn starts_with() -> TwoStringPredicate { TwoStringPredicate(StrExt::starts_with) }
fn contains() -> TwoStringPredicate { TwoStringPredicate(StrExt::contains) }

struct Substring(for<'s> fn(&'s str, &'s str) -> &'s str);

impl Function for Substring {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let s = self.0(&*args[0], &*args[1]);
        Ok(Value::String(s.to_string()))
    }
}

fn substring_before() -> Substring {
    fn inner<'a>(haystack: &'a str, needle: &'a str) -> &'a str {
        match haystack.find_str(needle) {
            Some(pos) => &haystack[..pos],
            None => "",
        }
    }
    Substring(inner)
}

fn substring_after() -> Substring {
    fn inner<'a>(haystack: &'a str, needle: &'a str) -> &'a str {
        match haystack.find_str(needle) {
            Some(pos) => &haystack[pos + needle.len()..],
            None => "",
        }
    }
    Substring(inner)
}

struct Not;

impl Function for Not {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Boolean(v) => Ok(Value::Boolean(!v)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Boolean)),
        }
    }
}

struct BooleanLiteral(bool);

impl Function for BooleanLiteral {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(self.0))
    }
}

fn true_fn() -> BooleanLiteral { BooleanLiteral(true) }
fn false_fn() -> BooleanLiteral { BooleanLiteral(false) }

struct NumberConvert(fn(f64) -> f64);

impl Function for NumberConvert {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = try!(one_number(args));
        Ok(Value::Number(self.0(arg)))
    }
}

fn floor() -> NumberConvert { NumberConvert(Float::floor) }
fn ceiling() -> NumberConvert { NumberConvert(Float::ceil) }

pub fn register_core_functions(functions: &mut Functions) {
    functions.insert("last".to_string(), box Last);
    functions.insert("position".to_string(), box Position);
    functions.insert("count".to_string(), box Count);
    functions.insert("concat".to_string(), box Concat);
    functions.insert("starts-with".to_string(), box starts_with());
    functions.insert("contains".to_string(), box contains());
    functions.insert("substring-before".to_string(), box substring_before());
    functions.insert("substring-after".to_string(), box substring_after());
    functions.insert("not".to_string(), box Not);
    functions.insert("true".to_string(), box true_fn());
    functions.insert("false".to_string(), box false_fn());
    functions.insert("floor".to_string(), box floor());
    functions.insert("ceiling".to_string(), box ceiling());
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use document::Package;
    use super::super::{EvaluationContext,LiteralValue,Value,Functions,Variables,Namespaces};
    use super::super::nodeset::ToNode;
    use super::{
        Function,
        Error,
        Last,
        Position,
        Count,
        Concat,
    };

    struct Setup<'d> {
        functions: Functions,
        variables: Variables<'d>,
        namespaces: Namespaces,
    }

    impl<'d> Setup<'d> {
        fn new() -> Setup<'d> {
            Setup {
                functions: HashMap::new(),
                variables: HashMap::new(),
                namespaces: HashMap::new(),
            }
        }

        fn evaluate<N, F>(&self, node: N, f: F, args: Vec<Value<'d>>)
            -> Result<Value<'d>, Error>
            where N: ToNode<'d>,
                  F: Function
        {
            let context = EvaluationContext::new(
                node, &self.functions, &self.variables, &self.namespaces
            );
            f.evaluate(&context, args)
        }
    }

    fn evaluate_literal<F>(f: F, args: Vec<LiteralValue>) -> Result<LiteralValue, Error>
        where F: Function
    {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let args = args.into_iter().map(|a| a.into_value()).collect();

        let r = setup.evaluate(doc.root(), f, args);

        r.map(|r| r.into_literal_value())
    }

    #[test]
    fn last_returns_context_size() {
        let r = evaluate_literal(Last, vec![]);
        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn position_returns_context_position() {
        let r = evaluate_literal(Position, vec![]);

        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn count_counts_nodes_in_nodeset() {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let nodeset = nodeset![doc.root()];
        let r = setup.evaluate(doc.root(), Count, vec![Value::Nodes(nodeset)]);

        assert_eq!(Ok(Value::Number(1.0)), r);
    }

    #[test]
    fn concat_combines_strings() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String(" ".to_string()),
                        LiteralValue::String("world".to_string())];
        let r = evaluate_literal(Concat, args);

        assert_eq!(Ok(LiteralValue::String("hello world".to_string())), r);
    }

    #[test]
    fn starts_with_checks_prefixes() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String("he".to_string())];
        let r = evaluate_literal(super::starts_with(), args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn contains_looks_for_a_needle() {
        let args = vec![LiteralValue::String("astronomer".to_string()),
                        LiteralValue::String("ono".to_string())];
        let r = evaluate_literal(super::contains(), args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn substring_before_slices_before() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(super::substring_before(), args);

        assert_eq!(Ok(LiteralValue::String("1999".to_string())), r);
    }

    #[test]
    fn substring_after_slices_after() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(super::substring_after(), args);

        assert_eq!(Ok(LiteralValue::String("04/01".to_string())), r);
    }

    #[test]
    fn floor_rounds_down() {
        let r = evaluate_literal(super::floor(), vec![LiteralValue::Number(199.99)]);

        assert_eq!(Ok(LiteralValue::Number(199.0)), r);
    }

    #[test]
    fn ceiling_rounds_up() {
        let r = evaluate_literal(super::ceiling(), vec![LiteralValue::Number(199.99)]);

        assert_eq!(Ok(LiteralValue::Number(200.0)), r);
    }
}
<commit_msg>Add XPath core function round()<commit_after>use std::{error,fmt};
use std::num::Float;

use super::{EvaluationContext,Functions,Value};

pub trait Function {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>;
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum ArgumentType {
    Nodeset,
    Boolean,
    Number,
    String,
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum Error {
    TooManyArguments{ expected: usize, actual: usize },
    NotEnoughArguments{ expected: usize, actual: usize },
    WrongType{ expected: ArgumentType, actual: ArgumentType },
}

impl Error {
    fn wrong_type(actual: &Value, expected: ArgumentType) -> Error {
        let actual = match *actual {
            Value::Nodes(..)   => ArgumentType::Nodeset,
            Value::String(..)  => ArgumentType::String,
            Value::Number(..)  => ArgumentType::Number,
            Value::Boolean(..) => ArgumentType::Boolean,
        };

        Error::WrongType {
            expected: expected,
            actual: actual
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            TooManyArguments{..}   => "too many arguments",
            NotEnoughArguments{..} => "not enough arguments",
            WrongType{..}          => "argument of wrong type",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            TooManyArguments{expected, actual} => {
                write!(fmt, "too many arguments, expected {} but had {}", expected, actual)
            },
            NotEnoughArguments{expected, actual} => {
                write!(fmt, "not enough arguments, expected {} but had {}", expected, actual)
            },
            WrongType{expected, actual} => {
                write!(fmt, "argument was the wrong type, expected {:?} but had {:?}", expected, actual)
            },
        }
    }
}

fn minimum_arg_count<T>(args: &Vec<T>, minimum: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < minimum {
        Err(Error::NotEnoughArguments{expected: minimum, actual: actual})
    } else {
        Ok(())
    }
}

fn exact_arg_count<T>(args: &Vec<T>, expected: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < expected {
        Err(Error::NotEnoughArguments{ expected: expected, actual: actual })
    } else if actual > expected {
        Err(Error::TooManyArguments{ expected: expected, actual: actual })
    } else {
        Ok(())
    }
}

fn string_args(args: Vec<Value>) -> Result<Vec<String>, Error> {
    fn string_arg(v: Value) -> Result<String, Error> {
        match v {
            Value::String(s) => Ok(s),
            _ => Err(Error::wrong_type(&v, ArgumentType::String)),
        }
    }

    args.into_iter().map(string_arg).collect()
}

fn one_number(args: Vec<Value>) -> Result<f64, Error> {
    match &args[0] {
        &Value::Number(v) => Ok(v),
        a => Err(Error::wrong_type(a, ArgumentType::Number)),
    }
}

struct Last;

impl Function for Last {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.size() as f64))
    }
}

struct Position;

impl Function for Position {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.position() as f64))
    }
}

struct Count;

impl Function for Count {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Nodes(ref nodeset) => Ok(Value::Number(nodeset.size() as f64)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Nodeset)),
        }
    }
}

struct Concat;

impl Function for Concat {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(minimum_arg_count(&args, 2));
        let args = try!(string_args(args));
        Ok(Value::String(args.concat()))
    }
}

struct TwoStringPredicate(fn(&str, &str) -> bool);

impl Function for TwoStringPredicate {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = self.0(&*args[0], &*args[1]);
        Ok(Value::Boolean(v))
    }
}

fn starts_with() -> TwoStringPredicate { TwoStringPredicate(StrExt::starts_with) }
fn contains() -> TwoStringPredicate { TwoStringPredicate(StrExt::contains) }

struct Substring(for<'s> fn(&'s str, &'s str) -> &'s str);

impl Function for Substring {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let s = self.0(&*args[0], &*args[1]);
        Ok(Value::String(s.to_string()))
    }
}

fn substring_before() -> Substring {
    fn inner<'a>(haystack: &'a str, needle: &'a str) -> &'a str {
        match haystack.find_str(needle) {
            Some(pos) => &haystack[..pos],
            None => "",
        }
    }
    Substring(inner)
}

fn substring_after() -> Substring {
    fn inner<'a>(haystack: &'a str, needle: &'a str) -> &'a str {
        match haystack.find_str(needle) {
            Some(pos) => &haystack[pos + needle.len()..],
            None => "",
        }
    }
    Substring(inner)
}

struct Not;

impl Function for Not {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Boolean(v) => Ok(Value::Boolean(!v)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Boolean)),
        }
    }
}

struct BooleanLiteral(bool);

impl Function for BooleanLiteral {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(self.0))
    }
}

fn true_fn() -> BooleanLiteral { BooleanLiteral(true) }
fn false_fn() -> BooleanLiteral { BooleanLiteral(false) }

struct NumberConvert(fn(f64) -> f64);

impl Function for NumberConvert {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = try!(one_number(args));
        Ok(Value::Number(self.0(arg)))
    }
}

fn floor() -> NumberConvert { NumberConvert(Float::floor) }
fn ceiling() -> NumberConvert { NumberConvert(Float::ceil) }

// http://stackoverflow.com/a/28124775/155423
fn round_ties_to_positive_infinity(x: f64) -> f64 {
    let y = x.floor();
    if x == y {
        x
    } else {
        let z = (2.0*x-y).floor();
        z * x.signum() // Should use copysign
    }
}

fn round() -> NumberConvert { NumberConvert(round_ties_to_positive_infinity) }

pub fn register_core_functions(functions: &mut Functions) {
    functions.insert("last".to_string(), box Last);
    functions.insert("position".to_string(), box Position);
    functions.insert("count".to_string(), box Count);
    functions.insert("concat".to_string(), box Concat);
    functions.insert("starts-with".to_string(), box starts_with());
    functions.insert("contains".to_string(), box contains());
    functions.insert("substring-before".to_string(), box substring_before());
    functions.insert("substring-after".to_string(), box substring_after());
    functions.insert("not".to_string(), box Not);
    functions.insert("true".to_string(), box true_fn());
    functions.insert("false".to_string(), box false_fn());
    functions.insert("floor".to_string(), box floor());
    functions.insert("ceiling".to_string(), box ceiling());
    functions.insert("round".to_string(), box round());
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::num::Float;
    use document::Package;
    use super::super::{EvaluationContext,LiteralValue,Value,Functions,Variables,Namespaces};
    use super::super::nodeset::ToNode;
    use super::{
        Function,
        Error,
        Last,
        Position,
        Count,
        Concat,
    };

    struct Setup<'d> {
        functions: Functions,
        variables: Variables<'d>,
        namespaces: Namespaces,
    }

    impl<'d> Setup<'d> {
        fn new() -> Setup<'d> {
            Setup {
                functions: HashMap::new(),
                variables: HashMap::new(),
                namespaces: HashMap::new(),
            }
        }

        fn evaluate<N, F>(&self, node: N, f: F, args: Vec<Value<'d>>)
            -> Result<Value<'d>, Error>
            where N: ToNode<'d>,
                  F: Function
        {
            let context = EvaluationContext::new(
                node, &self.functions, &self.variables, &self.namespaces
            );
            f.evaluate(&context, args)
        }
    }

    fn evaluate_literal<F>(f: F, args: Vec<LiteralValue>) -> Result<LiteralValue, Error>
        where F: Function
    {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let args = args.into_iter().map(|a| a.into_value()).collect();

        let r = setup.evaluate(doc.root(), f, args);

        r.map(|r| r.into_literal_value())
    }

    #[test]
    fn last_returns_context_size() {
        let r = evaluate_literal(Last, vec![]);
        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn position_returns_context_position() {
        let r = evaluate_literal(Position, vec![]);

        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn count_counts_nodes_in_nodeset() {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let nodeset = nodeset![doc.root()];
        let r = setup.evaluate(doc.root(), Count, vec![Value::Nodes(nodeset)]);

        assert_eq!(Ok(Value::Number(1.0)), r);
    }

    #[test]
    fn concat_combines_strings() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String(" ".to_string()),
                        LiteralValue::String("world".to_string())];
        let r = evaluate_literal(Concat, args);

        assert_eq!(Ok(LiteralValue::String("hello world".to_string())), r);
    }

    #[test]
    fn starts_with_checks_prefixes() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String("he".to_string())];
        let r = evaluate_literal(super::starts_with(), args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn contains_looks_for_a_needle() {
        let args = vec![LiteralValue::String("astronomer".to_string()),
                        LiteralValue::String("ono".to_string())];
        let r = evaluate_literal(super::contains(), args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn substring_before_slices_before() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(super::substring_before(), args);

        assert_eq!(Ok(LiteralValue::String("1999".to_string())), r);
    }

    #[test]
    fn substring_after_slices_after() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(super::substring_after(), args);

        assert_eq!(Ok(LiteralValue::String("04/01".to_string())), r);
    }

    fn assert_number<F>(f: F, val: f64, expected: f64)
        where F: Function
    {
        let r = evaluate_literal(f, vec![LiteralValue::Number(val)]);

        if expected.is_nan() {
            match r {
                Ok(LiteralValue::Number(a)) => assert!(a.is_nan(), "{} should be NaN", a),
                _ => assert!(false, "{:?} did not evaluate correctly", r),
            }
        } else {
            assert_eq!(Ok(LiteralValue::Number(expected)), r);
        }
    }

    #[test]
    fn floor_rounds_down() {
        assert_number(super::floor(), 199.99, 199.0);
    }

    #[test]
    fn ceiling_rounds_up() {
        assert_number(super::ceiling(), 199.99, 200.0);
    }

    #[test]
    fn round_nan_to_nan() {
        assert_number(super::round(), Float::nan(), Float::nan());
    }

    #[test]
    fn round_pos_inf_to_pos_inf() {
        assert_number(super::round(), Float::infinity(), Float::infinity());
    }

    #[test]
    fn round_neg_inf_to_neg_inf() {
        assert_number(super::round(), Float::neg_infinity(), Float::neg_infinity());
    }

    #[test]
    fn round_pos_zero_to_pos_zero() {
        assert_number(super::round(), Float::zero(), Float::zero());
    }

    #[test]
    fn round_neg_zero_to_neg_zero() {
        assert_number(super::round(), Float::neg_zero(), Float::neg_zero());
    }

    #[test]
    fn round_neg_zero_point_five_to_neg_zero() {
        assert_number(super::round(), -0.5, Float::neg_zero());
    }

    #[test]
    fn round_pos_zero_point_five_to_pos_one() {
        assert_number(super::round(), 0.5, 1.0);
    }
}
<|endoftext|>


<commit_before>use ::events;
use ::object;

use piston_window;
use gfx_device_gl;

struct Game {
    events: events::Events,
    player: object::Object,
}

impl Game {
    fn new(sprite: piston_window::Texture<gfx_device_gl::Resources>) -> Game {
        Game { player: object::Object::new(Some(sprite)), up: false, down: false, left: false, right: false }
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        if self.events.is_up()   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.events.is_down() { self.player.mov(0.0, 150.0 * args.dt); }
        if self.events.is_left() { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.events.is_right() { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &piston_window::Input) {
        self.events.process_events(&input);
    }
}
<commit_msg>Work in progress<commit_after>use ::events;
use ::object;

use piston_window;
use gfx_device_gl;

struct Game {
    events: events::Events,
    player: object::Object,
}

impl Game {
    fn new(sprite: piston_window::Texture<gfx_device_gl::Resources>) -> Game {
        Game { events: events::Events::new(), player: object::Object::new(Some(sprite)) }
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        if self.events.is_up()   { self.player.mov(0.0, -150.0 * args.dt); }
        if self.events.is_down() { self.player.mov(0.0, 150.0 * args.dt); }
        if self.events.is_left() { self.player.mov(-150.0 * args.dt, 0.0); }
        if self.events.is_right() { self.player.mov(150.0 * args.dt, 0.0); }
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_input(&mut self, input: &piston_window::Input) {
        self.events.process_events(&input);
    }
}
<|endoftext|>