<commit_before>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            } else {
                self.socket.flush()?;
            }
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            // FIXME: having the body here is too verbose, impl Display on frame instead: trace!("will write to buffer: {:?}", next_msg);
            trace!("Will write to buffer");
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<commit_msg>flush the socket more often<commit_after>use crate::{
    buffer::Buffer, connection::Connection, connection_status::ConnectionState, Error,
    PromiseResolver, Result,
};
use amq_protocol::frame::{gen_frame, parse_frame, AMQPFrame, GenError};
use log::{error, trace};
use mio::{event::Source, Events, Interest, Poll, Token, Waker};
use std::{
    collections::VecDeque,
    io::{self, Read, Write},
    sync::Arc,
    thread::Builder as ThreadBuilder,
    time::{Duration, Instant},
};

pub(crate) const SOCKET: Token = Token(1);
const WAKER: Token = Token(2);

const FRAMES_STORAGE: usize = 32;

#[derive(Debug, PartialEq)]
enum Status {
    Initial,
    Setup,
    Stop,
}

pub struct IoLoop<T> {
    connection: Connection,
    socket: T,
    status: Status,
    poll: Poll,
    waker: Arc<Waker>,
    frame_size: usize,
    receive_buffer: Buffer,
    send_buffer: Buffer,
    can_write: bool,
    can_read: bool,
    poll_timeout: Option<Duration>,
    serialized_frames: VecDeque<(u64, Option<PromiseResolver<()>>)>,
    last_write: Instant,
}

impl<T: Source + Read + Write + Send + 'static> IoLoop<T> {
    pub(crate) fn new(
        connection: Connection,
        socket: T,
        poll: Option<(Poll, Token)>,
    ) -> Result<Self> {
        let (poll, registered) = poll
            .map(|t| Ok((t.0, true)))
            .unwrap_or_else(|| Poll::new().map(|poll| (poll, false)))?;
        let frame_size = std::cmp::max(8192, connection.configuration().frame_max() as usize);
        let waker = Arc::new(Waker::new(poll.registry(), WAKER)?);
        let mut inner = Self {
            connection,
            socket,
            status: Status::Initial,
            poll,
            waker,
            frame_size,
            receive_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            send_buffer: Buffer::with_capacity(FRAMES_STORAGE * frame_size),
            can_write: false,
            can_read: false,
            poll_timeout: None,
            serialized_frames: VecDeque::default(),
            last_write: Instant::now(),
        };
        if registered {
            inner.poll.registry().reregister(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        } else {
            inner.poll.registry().register(
                &mut inner.socket,
                SOCKET,
                Interest::READABLE | Interest::WRITABLE,
            )?;
        }
        Ok(inner)
    }

    fn ensure_setup(&mut self) -> Result<()> {
        if self.status != Status::Setup && self.connection.status().connected() {
            let frame_max = self.connection.configuration().frame_max() as usize;
            self.frame_size = std::cmp::max(self.frame_size, frame_max);
            self.receive_buffer.grow(FRAMES_STORAGE * self.frame_size);
            self.send_buffer.grow(FRAMES_STORAGE * self.frame_size);
            let heartbeat = self.connection.configuration().heartbeat();
            if heartbeat != 0 {
                let heartbeat = Duration::from_millis(u64::from(heartbeat) * 500); // * 1000 (ms) / 2 (half the negociated timeout)
                self.poll_timeout = Some(heartbeat);
            }
            self.status = Status::Setup;
        }
        Ok(())
    }

    fn has_data(&self) -> bool {
        self.connection.has_pending_frames()
            || self.send_buffer.available_data() > 0
            || !self.serialized_frames.is_empty()
    }

    fn can_write(&self) -> bool {
        self.can_write && self.has_data() && !self.connection.status().blocked()
    }

    fn can_read(&self) -> bool {
        self.can_read
    }

    fn can_parse(&self) -> bool {
        self.receive_buffer.available_data() > 0
    }

    fn should_continue(&self) -> bool {
        let connection_status = self.connection.status();
        (self.status == Status::Initial
            || connection_status.connected()
            || connection_status.closing())
            && self.status != Status::Stop
            && !connection_status.errored()
    }

    pub fn start(mut self) -> Result<()> {
        let waker = self.waker.clone();
        self.connection.clone().set_io_loop(
            ThreadBuilder::new()
                .name("io_loop".to_owned())
                .spawn(move || {
                    let mut events = Events::with_capacity(1024);
                    while self.should_continue() {
                        if let Err(err) = self.run(&mut events) {
                            self.cancel_serilized_frames(err)?;
                        }
                    }
                    Ok(())
                })?,
            waker,
        )
    }

    fn cancel_serilized_frames(&self, error: Error) -> Result<()> {
        for (_, resolver) in self.serialized_frames.iter() {
            if let Some(resolver) = resolver {
                resolver.swear(Err(error.clone()));
            }
        }
        Err(error)
    }

    fn poll_timeout(&self) -> Option<Duration> {
        self.poll_timeout.map(|timeout| {
            timeout
                .checked_sub(self.last_write.elapsed())
                .unwrap_or_else(|| Duration::from_secs(0))
        })
    }

    fn poll(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop poll");
        self.poll.poll(events, self.poll_timeout())?;
        trace!("io_loop poll done");
        for event in events.iter() {
            if event.token() == SOCKET {
                trace!("Got mio event for socket: {:?}", event);
                if event.is_read_closed() || event.is_write_closed() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionReset).into())?;
                }
                if event.is_error() {
                    self.critical_error(io::Error::from(io::ErrorKind::ConnectionAborted).into())?;
                }
                // Due to a bug in epoll/mio, it doesn't seem like we can trust this, it's sometimes missing when it should be there
                /*
                if event.is_readable() {
                    self.can_read = true;
                }
                */
                self.can_read = true;
                if event.is_writable() {
                    self.can_write = true;
                }
            }
        }
        Ok(())
    }

    fn run(&mut self, events: &mut Events) -> Result<()> {
        trace!("io_loop run");
        self.ensure_setup()?;
        self.poll(events)?;
        self.socket.flush()?;
        self.do_run()
    }

    fn do_run(&mut self) -> Result<()> {
        trace!(
            "io_loop do_run; can_read={}, can_write={}, has_data={}",
            self.can_read,
            self.can_write,
            self.has_data()
        );
        loop {
            self.write()?;
            if self.connection.status().closed() {
                self.status = Status::Stop;
            }
            if self.should_continue() {
                self.read()?;
            }
            self.parse()?;
            self.connection.poll_internal_promises()?;
            if self.should_heartbeat() {
                self.connection.send_heartbeat()?;
                // Update last_write so that if we cannot write yet to the socket, we don't enqueue countless heartbeats
                self.last_write = Instant::now();
            }
            if self.stop_looping() {
                self.maybe_continue()?;
                break;
            }
        }
        trace!(
            "io_loop do_run done; can_read={}, can_write={}, has_data={}, status={:?}",
            self.can_read,
            self.can_write,
            self.has_data(),
            self.status
        );
        Ok(())
    }

    fn should_heartbeat(&self) -> bool {
        if let Some(heartbeat_timeout) = self.poll_timeout {
            self.last_write.elapsed() > heartbeat_timeout
        } else {
            false
        }
    }

    fn stop_looping(&self) -> bool {
        !self.can_read()
            || !self.can_write()
            || self.status == Status::Stop
            || self.connection.status().errored()
    }

    fn has_pending_operations(&self) -> bool {
        self.status != Status::Stop && (self.can_read() || self.can_parse() || self.can_write())
    }

    fn maybe_continue(&mut self) -> Result<()> {
        if self.has_pending_operations() {
            trace!(
                "io_loop send continue; can_read={}, can_write={}, has_data={}",
                self.can_read,
                self.can_write,
                self.has_data()
            );
            self.send_continue()?;
        }
        Ok(())
    }

    fn critical_error(&mut self, error: Error) -> Result<()> {
        if let ConnectionState::SentProtocolHeader(resolver, ..) = self.connection.status().state()
        {
            resolver.swear(Err(error.clone()));
        }
        self.status = Status::Stop;
        self.connection.set_error(error.clone())?;
        Err(error)
    }

    fn write(&mut self) -> Result<()> {
        if self.can_write() {
            if let Err(e) = self.write_to_stream() {
                if e.wouldblock() {
                    self.can_write = false
                } else {
                    error!("error writing: {:?}", e);
                    self.critical_error(e)?;
                }
            }
        }
        Ok(())
    }

    fn read(&mut self) -> Result<()> {
        if self.can_read() {
            if let Err(e) = self.read_from_stream() {
                if e.wouldblock() {
                    self.can_read = false
                } else {
                    error!("error reading: {:?}", e);
                    self.critical_error(e)?;
                }
            }
            self.receive_buffer.shift_unless_available(self.frame_size);
        }
        Ok(())
    }

    fn send_continue(&mut self) -> Result<()> {
        self.waker.wake()?;
        Ok(())
    }

    fn write_to_stream(&mut self) -> Result<()> {
        self.serialize()?;

        let sz = self.send_buffer.write_to(&mut self.socket)?;

        if sz > 0 {
            self.last_write = Instant::now();

            trace!("wrote {} bytes", sz);
            self.send_buffer.consume(sz, true);

            let mut written = sz as u64;
            while written > 0 {
                if let Some((to_write, resolver)) = self.serialized_frames.pop_front() {
                    if written < to_write {
                        self.serialized_frames
                            .push_front((to_write - written, resolver));
                        trace!("{} to write to complete this frame", to_write - written);
                        written = 0;
                    } else {
                        if let Some(resolver) = resolver {
                            resolver.swear(Ok(()));
                        }
                        written -= to_write;
                    }
                } else {
                    error!(
                        "We've written {} but didn't expect to write anything",
                        written
                    );
                    break;
                }
            }

            if self.send_buffer.available_data() > 0 {
                // We didn't write all the data yet
                trace!("Still {} to write", self.send_buffer.available_data());
                self.send_continue()?;
            } else {
                self.socket.flush()?;
            }
        } else {
            error!("Socket was writable but we wrote 0, marking as wouldblock");
            self.can_write = false;
        }
        Ok(())
    }

    fn read_from_stream(&mut self) -> Result<()> {
        match self.connection.status().state() {
            ConnectionState::Closed => Ok(()),
            ConnectionState::Error => Err(Error::InvalidConnectionState(ConnectionState::Error)),
            _ => {
                self.receive_buffer
                    .read_from(&mut self.socket, false)
                    .map(|sz| {
                        trace!("read {} bytes", sz);
                        self.receive_buffer.fill(sz, false);
                    })?;
                Ok(())
            }
        }
    }

    fn serialize(&mut self) -> Result<()> {
        if let Some((next_msg, resolver)) = self.connection.next_frame() {
            // FIXME: having the body here is too verbose, impl Display on frame instead: trace!("will write to buffer: {:?}", next_msg);
            trace!("Will write to buffer");
            let checkpoint = self.send_buffer.checkpoint();
            let res = gen_frame(&next_msg)((&mut self.send_buffer).into());
            match res.map(|w| w.into_inner().1) {
                Ok(sz) => {
                    self.serialized_frames.push_back((sz, resolver));
                    Ok(())
                }
                Err(e) => {
                    self.send_buffer.rollback(checkpoint);
                    match e {
                        GenError::BufferTooSmall(_) => {
                            // Requeue msg
                            self.connection.requeue_frame((next_msg, resolver))?;
                            Ok(())
                        }
                        e => {
                            error!("error generating frame: {:?}", e);
                            let error = Error::SerialisationError(Arc::new(e));
                            self.connection.set_error(error.clone())?;
                            Err(error)
                        }
                    }
                }
            }
        } else {
            Ok(())
        }
    }

    fn parse(&mut self) -> Result<()> {
        if self.can_parse() {
            if let Some(frame) = self.do_parse()? {
                self.connection.handle_frame(frame)?;
            }
        }
        Ok(())
    }

    fn do_parse(&mut self) -> Result<Option<AMQPFrame>> {
        match parse_frame(self.receive_buffer.data()) {
            Ok((i, f)) => {
                let consumed = self.receive_buffer.offset(i);
                self.receive_buffer.consume(consumed, false);
                Ok(Some(f))
            }
            Err(e) => {
                if e.is_incomplete() {
                    self.receive_buffer.shift();
                    Ok(None)
                } else {
                    error!("parse error: {:?}", e);
                    let error = Error::ParsingError(e);
                    self.connection.set_error(error.clone())?;
                    Err(error)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use range::Range;

use {
    update,
    MetaReader,
    Rule,
};

/// Stores information about optional.
pub struct Optional {
    /// The optional rules.
    pub args: Vec<Rule>,
}

impl Optional {
    /// Parse optional.
    /// Returns the old state if any sub rule fails.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        mut offset: usize
    ) -> (Range, M::State)
        where M: MetaReader
    {
        let start_offset = offset;
        let mut success_state = state.clone();
        for sub_rule in &self.args {
            success_state = match sub_rule.parse(meta_reader, &success_state,
                                         chars, offset) {
                Ok((range, state)) => {
                    update(range, &mut chars, &mut offset);
                    state
                }
                Err(_) => {
                    return (Range::new(start_offset, 0), state.clone())
                }
            }
        }
        (Range::new(start_offset, offset - start_offset), success_state)
    }
}
<commit_msg>Added unit test for `Optional`<commit_after>use range::Range;

use {
    update,
    MetaReader,
    Rule,
};

/// Stores information about optional.
pub struct Optional {
    /// The optional rules.
    pub args: Vec<Rule>,
}

impl Optional {
    /// Parse optional.
    /// Returns the old state if any sub rule fails.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        mut chars: &[char],
        mut offset: usize
    ) -> (Range, M::State)
        where M: MetaReader
    {
        let start_offset = offset;
        let mut success_state = state.clone();
        for sub_rule in &self.args {
            success_state = match sub_rule.parse(meta_reader, &success_state,
                                         chars, offset) {
                Ok((range, state)) => {
                    update(range, &mut chars, &mut offset);
                    state
                }
                Err(_) => {
                    return (Range::new(start_offset, 0), state.clone())
                }
            }
        }
        (Range::new(start_offset, offset - start_offset), success_state)
    }
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use range::Range;
    use std::rc::Rc;

    #[test]
    fn fail_but_continue() {
        let text = "2";
        let chars: Vec<char> = text.chars().collect();
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let num: Rc<String> = Rc::new("num".into());
        // Will fail because text is expected first.
        let optional = Optional {
            args: vec![
                Rule::Text(Text {
                    allow_empty: true,
                    property: None
                }),
                Rule::Number(Number {
                    property: Some(num.clone())
                })
            ]
        };
        let res = optional.parse(&mut tokenizer, &s, &chars, 0);
        assert_eq!(res, (Range::new(0, 0), TokenizerState(0)));
        assert_eq!(tokenizer.tokens.len(), 0);
    }
}
<|endoftext|>


<commit_before>use sass::value_part::ValuePart;
use sass::number_value::NumberValue;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;
extern crate collections;

#[derive(Debug)]
pub struct Evaluator<'a, T> {
    value_tokens: T,
    variables: Option<&'a HashMap<String, String>>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
    paren_level: i32,
}

impl<'a> Evaluator<'a, ValueTokenizer<'a>> {
    pub fn new_from_string(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a, ValueTokenizer<'a>>
    {
        Evaluator {
            value_tokens: ValueTokenizer::new(&original),
            variables: Some(&variables),
            value_stack: Vec::new(),
            op_stack: Vec::new(),
            paren_level: 0,
        }
    }
}

impl<'a> Evaluator<'a, collections::vec::IntoIter<ValuePart<'a>>> {
    pub fn new(value_tokens: Vec<ValuePart<'a>>) -> Evaluator<'a, collections::vec::IntoIter<ValuePart<'a>>>
    {
        Evaluator {
            value_tokens: value_tokens.into_iter(),
            variables: None,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
            paren_level: 0,
        }
    }
}

impl<'a, T> Evaluator<'a, T>
where T: Iterator<Item = ValuePart<'a>>
{
    pub fn evaluate(&mut self) -> ValuePart<'a> {
        let mut last_was_an_operator = true;

        while let Some(part) = self.value_tokens.next() {
            match part {
                ValuePart::Variable(name) => {
                    match self.variables {
                        Some(vars) => {
                            match vars.get(&(*name).to_string()) {
                                Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                                None => self.value_stack.push(ValuePart::String(name)),
                            }
                        },
                        None => self.value_stack.push(ValuePart::String(name)),
                    }
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        while !self.op_stack.is_empty() && self.op_stack.last() != Some(&Op::LeftParen) {
                            self.math_machine();
                        }
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        }
                        self.op_stack.pop();
                        last_was_an_operator = false;
                        self.paren_level -= 1;
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                        self.paren_level += 1;
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    }
                },
                other => panic!("Got unexpected ValuePart {:?}", other),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        if self.value_stack.len() > 1 {
            // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
            ValuePart::List(self.value_stack.clone())
        } else {
            self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)))
        }
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().unwrap_or(Op::Plus);
        let second = self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)));
        let first  = self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)));
        self.value_stack.push(op.apply(first, second, self.paren_level));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::collections::HashMap;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new_from_string("foo $bar 199.82 baz $quux", &vars).evaluate();

        assert_eq!(
            ValuePart::List(vec![
                ValuePart::String(Borrowed("foo")),
                ValuePart::List(vec![
                    ValuePart::String(Borrowed("4")),
                    ValuePart::Number(NumberValue::from_scalar(199.82))
                ]),
                ValuePart::String(Borrowed("baz")),
                ValuePart::String(Borrowed("3px 10px"))
            ]),
            answer
        );
    }

    #[test]
    fn it_adds() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(3.0)), answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(3.75)), answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let answer = Evaluator::new(vec![
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::RightParen),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(1.5)), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("23")),
            ValuePart::Number(NumberValue::from_scalar(4.0))
        ]), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list_in_a_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Operator(Op::RightParen),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("23")),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]), answer);
    }

    #[test]
    fn it_divides_because_parens_and_string_concats_because_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(10.0)),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("10.5")),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
        ]), answer);
    }

    #[test]
    fn it_does_not_divide_when_slash_is_separating() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(15.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::Number(NumberValue::from_scalar(15.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]), answer);
    }

    #[test]
    fn it_does_divide_when_other_math_is_involved() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
        ]).evaluate();

        assert_eq!(ValuePart::Number(NumberValue::computed(1.0)), answer);
    }
}<commit_msg>you are here<commit_after>use sass::value_part::ValuePart;
use sass::number_value::NumberValue;
use sass::op::Op;
use value_tokenizer::ValueTokenizer;

use std::borrow::Cow::Borrowed;
use std::collections::HashMap;
extern crate collections;

#[derive(Debug)]
pub struct Evaluator<'a, T> {
    value_tokens: T,
    variables: Option<&'a HashMap<String, String>>,
    value_stack: Vec<ValuePart<'a>>,
    op_stack: Vec<Op>,
    paren_level: i32,
}

impl<'a> Evaluator<'a, ValueTokenizer<'a>> {
    pub fn new_from_string(original: &'a str, variables: &'a HashMap<String, String>) -> Evaluator<'a, ValueTokenizer<'a>>
    {
        Evaluator {
            value_tokens: ValueTokenizer::new(&original),
            variables: Some(&variables),
            value_stack: Vec::new(),
            op_stack: Vec::new(),
            paren_level: 0,
        }
    }
}

impl<'a> Evaluator<'a, collections::vec::IntoIter<ValuePart<'a>>> {
    pub fn new(value_tokens: Vec<ValuePart<'a>>) -> Evaluator<'a, collections::vec::IntoIter<ValuePart<'a>>>
    {
        Evaluator {
            value_tokens: value_tokens.into_iter(),
            variables: None,
            value_stack: Vec::new(),
            op_stack: Vec::new(),
            paren_level: 0,
        }
    }
}

impl<'a, T> Evaluator<'a, T>
where T: Iterator<Item = ValuePart<'a>>
{
    pub fn evaluate(&mut self) -> ValuePart<'a> {
        let mut last_was_an_operator = true;

        while let Some(part) = self.value_tokens.next() {
            match part {
                ValuePart::Variable(name) => {
                    match self.variables {
                        Some(vars) => {
                            match vars.get(&(*name).to_string()) {
                                Some(ref v) => self.value_stack.push(ValuePart::String(Borrowed(v))),
                                None => self.value_stack.push(ValuePart::String(name)),
                            }
                        },
                        None => self.value_stack.push(ValuePart::String(name)),
                    }
                    last_was_an_operator = false;
                },
                s @ ValuePart::String(..) => {
                    self.value_stack.push(s);
                    last_was_an_operator = false;
                },
                n @ ValuePart::Number(..) => {
                    if last_was_an_operator {
                        self.value_stack.push(n);
                    } else {
                        while !self.op_stack.is_empty() && self.op_stack.last() != Some(&Op::LeftParen) {
                            self.math_machine();
                        }
                        let list_starter = self.value_stack.pop().expect("No expected list starter on the value stack!");
                        let list_parts = match list_starter {
                            ValuePart::List(mut v) => {
                                v.push(n);
                                v
                            },
                            other => vec![other, n],
                        };
                        self.value_stack.push(ValuePart::List(list_parts));
                    }
                    last_was_an_operator = false;
                },
                ValuePart::Operator(ref o) => {
                    if *o == Op::RightParen {
                        let mut last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        while last_operator != Op::LeftParen {
                            self.math_machine();
                            last_operator = self.op_stack.last().unwrap_or(&Op::LeftParen).clone();
                        }
                        self.op_stack.pop();
                        last_was_an_operator = false;
                        self.paren_level -= 1;
                    } else if *o == Op::LeftParen {
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                        self.paren_level += 1;
                    } else {
                        if let Some(&last_operator) = self.op_stack.last() {
                            if last_operator.same_or_greater_precedence(*o) {
                                self.math_machine();
                            }
                        }
                        self.op_stack.push(*o);
                        last_was_an_operator = true;
                    }
                },
                other => panic!("Got unexpected ValuePart {:?}", other),
            }
        }

        while !self.op_stack.is_empty() {
            self.math_machine();
        }

        if self.value_stack.len() > 1 {
            // TODO: figure out how to make borrowck like not cloning this, it's cool i swear
            ValuePart::List(self.value_stack.clone())
        } else {
            self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)))
        }
    }

    fn math_machine(&mut self) {
        let op = self.op_stack.pop().unwrap_or(Op::Plus);
        let second = self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)));
        let first  = self.value_stack.pop().unwrap_or(ValuePart::Number(NumberValue::from_scalar(0.0)));
        self.value_stack.push(op.apply(first, second, self.paren_level));
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use sass::value_part::ValuePart;
    use sass::number_value::NumberValue;
    use sass::op::Op;
    use std::collections::HashMap;
    use std::borrow::Cow::Borrowed;

    #[test]
    fn it_subtitutes_variable_values() {
        let mut vars = HashMap::new();
        vars.insert("$bar".to_string(), "4".to_string());
        vars.insert("$quux".to_string(), "3px 10px".to_string());

        let answer = Evaluator::new_from_string("foo $bar 199.82 baz $quux", &vars).evaluate();

        assert_eq!(
            ValuePart::List(vec![
                ValuePart::String(Borrowed("foo")),
                ValuePart::List(vec![
                    ValuePart::String(Borrowed("4")),
                    ValuePart::Number(NumberValue::from_scalar(199.82))
                ]),
                ValuePart::String(Borrowed("baz")),
                ValuePart::String(Borrowed("3px 10px"))
            ]),
            answer
        );
    }

    #[test]
    fn it_divides_if_value_came_from_a_variable() {
        let mut vars = HashMap::new();
        vars.insert("$three".to_string(), "3".to_string());

        let answer = Evaluator::new_from_string("15 / $three", &vars).evaluate();

        assert_eq!(
            ValuePart::Number(NumberValue::from_scalar(5.0)),
            answer
        );
    }

    #[test]
    fn it_adds() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(3.0)), answer);
    }

    #[test]
    fn it_divides_and_adds_with_the_right_precedence() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(3.75)), answer);
    }

    #[test]
    fn it_gets_the_right_precedence_with_parens() {
        let answer = Evaluator::new(vec![
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::RightParen),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
        ]).evaluate();
        assert_eq!(ValuePart::Number(NumberValue::computed(1.5)), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("23")),
            ValuePart::Number(NumberValue::from_scalar(4.0))
        ]), answer);
    }

    #[test]
    fn it_does_string_concat_when_adding_to_list_in_a_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Operator(Op::RightParen),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("23")),
            ValuePart::Number(NumberValue::from_scalar(4.0)),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]), answer);
    }

    #[test]
    fn it_divides_because_parens_and_string_concats_because_list() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Operator(Op::LeftParen),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(10.0)),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::RightParen),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::String(Borrowed("10.5")),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
        ]), answer);
    }

    #[test]
    fn it_does_not_divide_when_slash_is_separating() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(15.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]).evaluate();

        assert_eq!(ValuePart::List(vec![
            ValuePart::Number(NumberValue::from_scalar(15.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(3.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(5.0)),
        ]), answer);
    }

    #[test]
    fn it_does_divide_when_other_math_is_involved() {
        let answer = Evaluator::new(vec![
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
            ValuePart::Operator(Op::Plus),
            ValuePart::Number(NumberValue::from_scalar(1.0)),
            ValuePart::Operator(Op::Slash),
            ValuePart::Number(NumberValue::from_scalar(2.0)),
        ]).evaluate();

        assert_eq!(ValuePart::Number(NumberValue::computed(1.0)), answer);
    }
}<|endoftext|>


<commit_before>pub use self::manager::Manager;

/// The pass manager infrastructure.
pub mod manager;
/// Passes which perform transformations.
pub mod transforms;
/// Passes which perform analysis.
pub mod analysis;
/// The pass registry.
pub mod registrar;

extern crate compiler_ir as ir;
#[macro_use]
extern crate compiler_util as util;

extern crate num;

/// A pass identifier.
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub struct Id(u32);

pub enum Info
{
    Analysis(Box<Analysis>),
    Transform(Box<Transform>),
}

impl Metadata for Info
{
    fn id(&self) -> Id {
        match *self {
            Info::Analysis(ref p) => p.id(),
            Info::Transform(ref p) => p.id(),
        }
    }

    fn dependencies(&self) -> &'static [Id] {
        match *self {
            Info::Analysis(ref p) => p.dependencies(),
            Info::Transform(ref p) => p.dependencies(),
        }
    }

    fn name(&self) -> &'static str {
        match *self {
            Info::Analysis(ref p) => p.name(),
            Info::Transform(ref p) => p.name(),
        }
    }
}

/// A pass over a set of instructions.
pub trait Metadata
{
    fn id(&self) -> Id;

    /// Gets the identifiers of the passes this pass
    /// depends on.
    fn dependencies(&self) -> &'static [Id] {
        &[]
    }

    fn name(&self) -> &'static str;
}

pub trait Analysis : Metadata
{
    /// Run the pass on an entire module.
    fn run_module(&mut self,
                  module: &ir::Module) {

        for global in module.globals() {
            self.run_global(global);
        }

        for func in module.functions() {
            self.run_function(func);
        }
    }

    /// Run the pass on a global variable.
    fn run_global(&mut self,
                  _: &ir::Global) {
        // do nothing unless overidden
    }

    /// Run the pass on a function.
    fn run_function(&mut self,
                    function: &ir::Function) {

        for bb in function.blocks() {
            self.run_block(bb);
        }
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self,
                 block: &ir::Block) {

        for value in block.values() {
            self.run_value_recursive(&value);
        }
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: &ir::Value) {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: &ir::Value) {

        // Recurse from the deepest node to the root node.
        for val in value.node.subvalues() {
            self.run_value_recursive(&val);
        }

        self.run_value(value)
    }
}

pub trait Transform : Metadata
{
    /// Run the pass on an entire module.
    fn run_module(&mut self,
                  module: ir::Module) -> ir::Module {
        module.map_globals(|a| self.run_global(a))
              .map_functions(|a,module| self.run_function(a,module))
    }

    /// Run the pass on a global.
    fn run_global(&mut self,
                  global: ir::Global)
        -> ir::Global {

        // do nothing unless overridden
        global
    }

    /// Run the pass on a function.
    fn run_function(&mut self,
                    function: ir::Function,
                    _module: &ir::Module)
        -> ir::Function {

        function.map_blocks(|a| self.run_block(a))
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self,
                 block: ir::Block)
        -> ir::Block {

        block.map_values(|a| self.run_value_recursive(a))
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: ir::Value) -> ir::Value {

        panic!("the {} pass is not implemented", self.name());
    }

    fn run_value_recursive(&mut self,
                           value: ir::Value) -> ir::Value {

        let val = ir::Value {
            // Recurse from the deepest node to the root node.
            node: value.node.map_subvalues(|v| self.run_value_recursive(v)),
        };

        self.run_value(val)
    }
}

<commit_msg>Remove unused #[macro_use]<commit_after>pub use self::manager::Manager;

/// The pass manager infrastructure.
pub mod manager;
/// Passes which perform transformations.
pub mod transforms;
/// Passes which perform analysis.
pub mod analysis;
/// The pass registry.
pub mod registrar;

extern crate compiler_ir as ir;
extern crate compiler_util as util;

extern crate num;

/// A pass identifier.
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
pub struct Id(u32);

pub enum Info
{
    Analysis(Box<Analysis>),
    Transform(Box<Transform>),
}

impl Metadata for Info
{
    fn id(&self) -> Id {
        match *self {
            Info::Analysis(ref p) => p.id(),
            Info::Transform(ref p) => p.id(),
        }
    }

    fn dependencies(&self) -> &'static [Id] {
        match *self {
            Info::Analysis(ref p) => p.dependencies(),
            Info::Transform(ref p) => p.dependencies(),
        }
    }

    fn name(&self) -> &'static str {
        match *self {
            Info::Analysis(ref p) => p.name(),
            Info::Transform(ref p) => p.name(),
        }
    }
}

/// A pass over a set of instructions.
pub trait Metadata
{
    fn id(&self) -> Id;

    /// Gets the identifiers of the passes this pass
    /// depends on.
    fn dependencies(&self) -> &'static [Id] {
        &[]
    }

    fn name(&self) -> &'static str;
}

pub trait Analysis : Metadata
{
    /// Run the pass on an entire module.
    fn run_module(&mut self,
                  module: &ir::Module) {

        for global in module.globals() {
            self.run_global(global);
        }

        for func in module.functions() {
            self.run_function(func);
        }
    }

    /// Run the pass on a global variable.
    fn run_global(&mut self,
                  _: &ir::Global) {
        // do nothing unless overidden
    }

    /// Run the pass on a function.
    fn run_function(&mut self,
                    function: &ir::Function) {

        for bb in function.blocks() {
            self.run_block(bb);
        }
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self,
                 block: &ir::Block) {

        for value in block.values() {
            self.run_value_recursive(&value);
        }
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: &ir::Value) {

        panic!("the pass is not implemented");
    }

    fn run_value_recursive(&mut self,
                           value: &ir::Value) {

        // Recurse from the deepest node to the root node.
        for val in value.node.subvalues() {
            self.run_value_recursive(&val);
        }

        self.run_value(value)
    }
}

pub trait Transform : Metadata
{
    /// Run the pass on an entire module.
    fn run_module(&mut self,
                  module: ir::Module) -> ir::Module {
        module.map_globals(|a| self.run_global(a))
              .map_functions(|a,module| self.run_function(a,module))
    }

    /// Run the pass on a global.
    fn run_global(&mut self,
                  global: ir::Global)
        -> ir::Global {

        // do nothing unless overridden
        global
    }

    /// Run the pass on a function.
    fn run_function(&mut self,
                    function: ir::Function,
                    _module: &ir::Module)
        -> ir::Function {

        function.map_blocks(|a| self.run_block(a))
    }

    /// Run the pass on a basic block.
    fn run_block(&mut self,
                 block: ir::Block)
        -> ir::Block {

        block.map_values(|a| self.run_value_recursive(a))
    }

    /// Run the pass on a value.
    fn run_value(&mut self,
                 _: ir::Value) -> ir::Value {

        panic!("the {} pass is not implemented", self.name());
    }

    fn run_value_recursive(&mut self,
                           value: ir::Value) -> ir::Value {

        let val = ir::Value {
            // Recurse from the deepest node to the root node.
            node: value.node.map_subvalues(|v| self.run_value_recursive(v)),
        };

        self.run_value(val)
    }
}

<|endoftext|>


<commit_before>use unix_socket::UnixStream;

use std::io;
use std::io::{Read, Write};

fn response(stream: &mut UnixStream) -> io::Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.push_all(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

fn open_lvmetad() {

    request(b"hello", false);
//    lvmetad_request(b"vg_list", true);
//    lvmetad_request(b"pv_list", true);
//    lvmetad_request(b"dump", false);

}

fn request(s: &[u8], token: bool) -> io::Result<Vec<u8>>{

    let path = "/run/lvm/lvmetad.socket";

    let mut stream = UnixStream::connect(path).unwrap();
    stream.write_all(b"request = \"").unwrap();
    stream.write_all(s).unwrap();
    stream.write_all(b"\"\n").unwrap();
    if token {
        stream.write_all(b"token = \"filter:0\"").unwrap();
        stream.write_all(b"\n").unwrap();
    }
    stream.write_all(b"\n##\n").unwrap();

    let response = try!(response(&mut stream));

    Ok(response)
}
<commit_msg>use a const string for lvmetad socket path<commit_after>use unix_socket::UnixStream;

use std::io;
use std::io::{Read, Write};

const LVMETAD_PATH: &'static str = "/run/lvm/lvmetad.socket";

fn response(stream: &mut UnixStream) -> io::Result<Vec<u8>> {
    let mut response = [0; 32];
    let mut v = Vec::new();

    loop {
        let bytes_read = try!(stream.read(&mut response));

        v.push_all(&response[..bytes_read]);

        if v.ends_with(b"\n##\n") {
            // drop the end marker
            let len = v.len() - 4;
            v.truncate(len);
            return Ok(v);
        }
    }
}

fn open_lvmetad() {

    request(b"hello", false);
//    lvmetad_request(b"vg_list", true);
//    lvmetad_request(b"pv_list", true);
//    lvmetad_request(b"dump", false);

}

fn request(s: &[u8], token: bool) -> io::Result<Vec<u8>>{

    let mut stream = UnixStream::connect(LVMETAD_PATH).unwrap();
    stream.write_all(b"request = \"").unwrap();
    stream.write_all(s).unwrap();
    stream.write_all(b"\"\n").unwrap();
    if token {
        stream.write_all(b"token = \"filter:0\"").unwrap();
        stream.write_all(b"\n").unwrap();
    }
    stream.write_all(b"\n##\n").unwrap();

    let response = try!(response(&mut stream));

    Ok(response)
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use rustc_serialize::json::Json;

use analysis::Analyzer;
use Value;

#[derive(Debug, PartialEq)]
pub enum FieldType {
    String,
    Binary,
    Number{size: u8, is_float: bool},
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType { FieldType::String }
}

#[derive(Debug)]
pub struct FieldMapping {
    data_type: FieldType,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    analyzer: Analyzer,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            analyzer: Analyzer::Standard,
        }
    }
}

impl FieldMapping {
    pub fn process_value(&self, value: Json) -> Option<Value> {
        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyzed strings become TSVectors. Unanalyzed strings become... strings
                        if self.analyzer == Analyzer::None {
                            Some(Value::String(string))
                        } else {
                            let tokens = self.analyzer.run(string);
                            Some(Value::TSVector(tokens))
                        }
                    }
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value(Json::String(strings.join(" ")))
                    }
                    _ => None
                }
            }
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

impl Mapping {
    pub fn from_json(json: &Json) -> Mapping {
        let json = json.as_object().unwrap();
        let properties_json = json.get("properties").unwrap().as_object().unwrap();

        // Parse fields
        let mut fields = HashMap::new();
        for (field_name, field_mapping_json) in properties_json.iter() {
            fields.insert(field_name.clone(), FieldMapping::from_json(field_mapping_json));
        }

        Mapping {
            fields: fields,
        }
    }
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
            }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl FieldMapping {
    pub fn from_json(json: &Json) -> FieldMapping {
        let json = json.as_object().unwrap();
        let mut field_mapping = FieldMapping::default();

        for (key, value) in json.iter() {
            match key.as_ref() {
                "type" => {
                    let type_name = value.as_string().unwrap();

                    field_mapping.data_type = match type_name.as_ref() {
                        "string" => FieldType::String,
                        "integer" => FieldType::Number{size: 64, is_float: false},
                        "boolean" => FieldType::Boolean,
                        "date" => FieldType::Date,
                        _ => {
                            // TODO; make this an error
                            warn!("unimplemented type name! {}", type_name);
                            FieldType::default()
                        }
                    };
                }
                "index" => {
                    let index = value.as_string().unwrap();
                    if index == "not_analyzed" {
                        field_mapping.analyzer = Analyzer::None;
                    } else {
                        // TODO: Implement other variants and make this an error
                        warn!("unimplemented index setting! {}", index);
                    }
                }
                "index_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        if s == &"edgengram_analyzer" {
                            field_mapping.analyzer = Analyzer::EdgeNGram;
                        }
                    }
                }
                "boost" => {
                    field_mapping.boost = value.as_f64().unwrap();
                }
                "store" => {
                    field_mapping.is_stored = parse_boolean(value);
                }
                "include_in_all" => {
                    field_mapping.is_in_all = parse_boolean(value);
                }
                _ => warn!("unimplemented field mapping key! {}", key)
            }

        }

        field_mapping
    }
}
<commit_msg>FieldMapping.process_value can now handle nulls and bools<commit_after>use std::collections::HashMap;

use rustc_serialize::json::Json;

use analysis::Analyzer;
use Value;

#[derive(Debug, PartialEq)]
pub enum FieldType {
    String,
    Binary,
    Number{size: u8, is_float: bool},
    Boolean,
    Date,
}

impl Default for FieldType {
    fn default() -> FieldType { FieldType::String }
}

#[derive(Debug)]
pub struct FieldMapping {
    data_type: FieldType,
    is_stored: bool,
    pub is_in_all: bool,
    boost: f64,
    analyzer: Analyzer,
}

impl Default for FieldMapping {
    fn default() -> FieldMapping {
        FieldMapping {
            data_type: FieldType::default(),
            is_stored: false,
            is_in_all: true,
            boost: 1.0f64,
            analyzer: Analyzer::Standard,
        }
    }
}

impl FieldMapping {
    pub fn process_value(&self, value: Json) -> Option<Value> {
        if value == Json::Null {
            return Some(Value::Null);
        }

        match self.data_type {
            FieldType::String => {
                match value {
                    Json::String(string) => {
                        // Analyzed strings become TSVectors. Unanalyzed strings become... strings
                        if self.analyzer == Analyzer::None {
                            Some(Value::String(string))
                        } else {
                            let tokens = self.analyzer.run(string);
                            Some(Value::TSVector(tokens))
                        }
                    }
                    Json::Array(array) => {
                        // Pack any strings into a vec, ignore nulls. Quit if we see anything else
                        let mut strings = Vec::new();

                        for item in array {
                            match item {
                                Json::String(string) => strings.push(string),
                                Json::Null => {}
                                _ => {
                                    return None;
                                }
                            }
                        }

                        self.process_value(Json::String(strings.join(" ")))
                    }
                    _ => None
                }
            }
            FieldType::Boolean => {
                Some(Value::Boolean(parse_boolean(&value)))
            }
            _ => None
        }
    }
}

#[derive(Debug)]
pub struct Mapping {
    pub fields: HashMap<String, FieldMapping>,
}

impl Mapping {
    pub fn from_json(json: &Json) -> Mapping {
        let json = json.as_object().unwrap();
        let properties_json = json.get("properties").unwrap().as_object().unwrap();

        // Parse fields
        let mut fields = HashMap::new();
        for (field_name, field_mapping_json) in properties_json.iter() {
            fields.insert(field_name.clone(), FieldMapping::from_json(field_mapping_json));
        }

        Mapping {
            fields: fields,
        }
    }
}

fn parse_boolean(json: &Json) -> bool {
    match *json {
        Json::Boolean(val) => val,
        Json::String(ref s) => {
            match s.as_ref() {
                "yes" => true,
                "no" => false,
                _ => {
                    warn!("bad boolean value {:?}", s);
                    false
                }
            }
        }
        _ => {
            // TODO: Raise error
            warn!("bad boolean value {:?}", json);
            false
        }
    }
}

impl FieldMapping {
    pub fn from_json(json: &Json) -> FieldMapping {
        let json = json.as_object().unwrap();
        let mut field_mapping = FieldMapping::default();

        for (key, value) in json.iter() {
            match key.as_ref() {
                "type" => {
                    let type_name = value.as_string().unwrap();

                    field_mapping.data_type = match type_name.as_ref() {
                        "string" => FieldType::String,
                        "integer" => FieldType::Number{size: 64, is_float: false},
                        "boolean" => FieldType::Boolean,
                        "date" => FieldType::Date,
                        _ => {
                            // TODO; make this an error
                            warn!("unimplemented type name! {}", type_name);
                            FieldType::default()
                        }
                    };
                }
                "index" => {
                    let index = value.as_string().unwrap();
                    if index == "not_analyzed" {
                        field_mapping.analyzer = Analyzer::None;
                    } else {
                        // TODO: Implement other variants and make this an error
                        warn!("unimplemented index setting! {}", index);
                    }
                }
                "index_analyzer" => {
                    if let Some(ref s) = value.as_string() {
                        if s == &"edgengram_analyzer" {
                            field_mapping.analyzer = Analyzer::EdgeNGram;
                        }
                    }
                }
                "boost" => {
                    field_mapping.boost = value.as_f64().unwrap();
                }
                "store" => {
                    field_mapping.is_stored = parse_boolean(value);
                }
                "include_in_all" => {
                    field_mapping.is_in_all = parse_boolean(value);
                }
                _ => warn!("unimplemented field mapping key! {}", key)
            }

        }

        field_mapping
    }
}
<|endoftext|>


<commit_before>/// Represents a position within a substrate.
/// Each position coordinate is mapped to an input of a CPPN.
pub trait Position {
    fn coords(&self) -> &[f64];
    fn distance(&self, other: &Self) -> f64;

    /// Linearly interpolates between `self` and `other`.
    /// For t = 0.0 this should return `self`. For t = 1.0 this
    /// should return `other`.
    fn interpolate(&self, other: &Self, t: f64) -> Self;

    fn interpolate_multi(&self, other: &Self, t: &Self) -> Self;
}

pub struct Position2d([f64; 2]);

impl Position2d {
    #[inline(always)]
    pub fn new(x: f64, y: f64) -> Position2d {
        Position2d([x, y])
    }

    #[inline(always)]
    pub fn x(&self) -> f64 {
        self.0[0]
    }

    #[inline(always)]
    pub fn y(&self) -> f64 {
        self.0[1]
    }

    #[inline(always)]
    pub fn xy(&self) -> (f64, f64) {
        (self.0[0], self.0[1])
    }

}

impl Position for Position2d {
    #[inline(always)]
    fn coords(&self) -> &[f64] {
        &self.0
    }

    #[inline]
    fn distance(&self, other: &Self) -> f64 {
        ((self.x() - other.x()).powi(2) + (self.y() - other.y()).powi(2)).sqrt()
    }

    fn interpolate(&self, other: &Self, t: f64) -> Self {
        let x = self.x() * (1.0 - t) + other.x() * t;
        let y = self.y() * (1.0 - t) + other.y() * t;
        Position2d([x, y])
    }

    fn interpolate_multi(&self, other: &Self, t: &Self) -> Self {
        let tx = t.x();
        let ty = t.y();
        let x = self.x() * (1.0 - tx) + other.x() * tx;
        let y = self.y() * (1.0 - ty) + other.y() * ty;
        Position2d([x, y])
    }
}

#[test]
fn test_interpolate_one_axis() {
    let a = Position2d::new(-1.0, 0.0);
    let b = Position2d::new(1.0, 0.0);

    assert_eq!((-1.0, 0.0), a.interpolate(&b, 0.0).xy());
    assert_eq!((0.0, 0.0),  a.interpolate(&b, 0.5).xy());
    assert_eq!((1.0, 0.0),  a.interpolate(&b, 1.0).xy());
}

#[test]
fn test_interpolate_two_axes() {
    let a = Position2d::new(-1.0, 1.0);
    let b = Position2d::new(1.0, -1.0);

    assert_eq!((-1.0, 1.0), a.interpolate(&b, 0.0).xy());
    assert_eq!((0.0, 0.0),  a.interpolate(&b, 0.5).xy());
    assert_eq!((1.0, -1.0),  a.interpolate(&b, 1.0).xy());
}

#[test]
fn test_interpolate_multi() {
    let a = Position2d::new(-1.0, 1.0);
    let b = Position2d::new(1.0, -1.0);

    assert_eq!((-1.0, -1.0), a.interpolate_multi(&b, &Position2d::new(0.0, 1.0)).xy());
    assert_eq!((0.0, 0.0),  a.interpolate_multi(&b, &Position2d::new(0.5, 0.5)).xy());
    assert_eq!((1.0, 1.0),  a.interpolate_multi(&b, &Position2d::new(1.0, 0.0)).xy());
}
<commit_msg>Add origin() method to trait Position<commit_after>/// Represents a position within a substrate.
/// Each position coordinate is mapped to an input of a CPPN.
pub trait Position {
    fn coords(&self) -> &[f64];
    fn distance(&self, other: &Self) -> f64;

    fn origin() -> Self;

    /// Linearly interpolates between `self` and `other`.
    /// For t = 0.0 this should return `self`. For t = 1.0 this
    /// should return `other`.
    fn interpolate(&self, other: &Self, t: f64) -> Self;

    fn interpolate_multi(&self, other: &Self, t: &Self) -> Self;
}

pub struct Position2d([f64; 2]);

impl Position2d {
    #[inline(always)]
    pub fn new(x: f64, y: f64) -> Position2d {
        Position2d([x, y])
    }

    #[inline(always)]
    pub fn x(&self) -> f64 {
        self.0[0]
    }

    #[inline(always)]
    pub fn y(&self) -> f64 {
        self.0[1]
    }

    #[inline(always)]
    pub fn xy(&self) -> (f64, f64) {
        (self.0[0], self.0[1])
    }

}

impl Position for Position2d {
    #[inline(always)]
    fn coords(&self) -> &[f64] {
        &self.0
    }

    #[inline(always)]
    fn origin() -> Self {
        Position2d::new(0.0, 0.0)
    }

    #[inline]
    fn distance(&self, other: &Self) -> f64 {
        ((self.x() - other.x()).powi(2) + (self.y() - other.y()).powi(2)).sqrt()
    }

    fn interpolate(&self, other: &Self, t: f64) -> Self {
        let x = self.x() * (1.0 - t) + other.x() * t;
        let y = self.y() * (1.0 - t) + other.y() * t;
        Position2d([x, y])
    }

    fn interpolate_multi(&self, other: &Self, t: &Self) -> Self {
        let tx = t.x();
        let ty = t.y();
        let x = self.x() * (1.0 - tx) + other.x() * tx;
        let y = self.y() * (1.0 - ty) + other.y() * ty;
        Position2d([x, y])
    }
}

#[test]
fn test_interpolate_one_axis() {
    let a = Position2d::new(-1.0, 0.0);
    let b = Position2d::new(1.0, 0.0);

    assert_eq!((-1.0, 0.0), a.interpolate(&b, 0.0).xy());
    assert_eq!((0.0, 0.0),  a.interpolate(&b, 0.5).xy());
    assert_eq!((1.0, 0.0),  a.interpolate(&b, 1.0).xy());
}

#[test]
fn test_interpolate_two_axes() {
    let a = Position2d::new(-1.0, 1.0);
    let b = Position2d::new(1.0, -1.0);

    assert_eq!((-1.0, 1.0), a.interpolate(&b, 0.0).xy());
    assert_eq!((0.0, 0.0),  a.interpolate(&b, 0.5).xy());
    assert_eq!((1.0, -1.0),  a.interpolate(&b, 1.0).xy());
}

#[test]
fn test_interpolate_multi() {
    let a = Position2d::new(-1.0, 1.0);
    let b = Position2d::new(1.0, -1.0);

    assert_eq!((-1.0, -1.0), a.interpolate_multi(&b, &Position2d::new(0.0, 1.0)).xy());
    assert_eq!((0.0, 0.0),  a.interpolate_multi(&b, &Position2d::new(0.5, 0.5)).xy());
    assert_eq!((1.0, 1.0),  a.interpolate_multi(&b, &Position2d::new(1.0, 0.0)).xy());
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
extern crate serde_json;
use std::process::Command;
extern crate mime;
use std::collections::BTreeMap;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint { es_cnx_string: url }.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    let bragi_get = |q| {
        iron_test::request::get(&format!("http://localhost:3000{}", q),
                                iron::Headers::new(),
                                &handler)
            .unwrap()
    };
    let to_json = |r| -> serde_json::Value {
        let s = iron_test::response::extract_body_to_string(r);
        serde_json::from_str(&s).unwrap()
    };
    let get_results = |r| -> Vec<_> {
        to_json(r)
            .find("features")
            .expect("wrongly formated bragi response")
            .as_array()
            .expect("features must be array")
            .iter()
            .map(|f| {
                f.pointer("/properties/geocoding")
                 .expect("no geocoding object in bragi response")
                 .as_object()
                 .unwrap()
                 .clone()
            })
            .collect()
    };

    // Call status
    let resp = bragi_get("/status");
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body,
               r#"{"version":"1.1.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = bragi_get("/autocomplete?q=15 Rue Hector Malot, (Paris)");
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":null,"#,
                         r#""city":null,"administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // A(48.846431 2.376488)
    // B(48.846430 2.376306)
    // C(48.846606 2.376309)
    // D(48.846603 2.376486)
    // R(48.846495 2.376378) : 15 Rue Hector Malot, (Paris)
    // E(48.846452 2.376580) : 18 Rue Hector Malot, (Paris)

    //             E
    //
    //      A ---------------------D
    //      |                      |
    //      |         R            |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where house number in shape
    let mut header = iron::Headers::new();
    let mime: mime::Mime = "application/json".parse().unwrap();
    header.set(iron::headers::ContentType(mime));
    let resp = iron_test::request::post("http://localhost:3000/autocomplete?q=15 Rue Hector \
                                        Malot, (Paris)",
                                       header.clone(),
                                       r#"{"geometry":{"type":"Polygon","coordinates":[[[48.846431,2.376488],[48.846430,2.376306],[48.846606,2.376309],[ 48.846603,2.376486]]]}}"#,
                                       &handler)
                   .unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // Search with shape where house number out shape
    let resp = iron_test::request::post("http://localhost:3000/autocomplete?q=18 Rue Hector \
                                        Malot, (Paris)",
                                       header,
                                       r#"{"geometry":{"type":"Polygon","coordinates":[[[48.846431,2.376488],[48.846430,2.376306],[48.846606,2.376309],[ 48.846603,2.376486]]]}}"#,
                                       &handler)
                   .unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","geocoding":{"version":"0.1.0","query":""},"features":[]}"#);
    assert_eq!(result_body, result);

    // test with a lon/lat
    // in the dataset there are 2 '20 rue hector malot', one in paris and one in trifouilli-les-oies
    // let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hect mal")); // in the mean time we time our prefix search_query
    // assert_eq!(all_20.len(), 2);
    // the first one is paris
    // TODO uncomment this test, for the moment since osm is not loaded, the order is random
    // assert_eq!(get_labels(&all_20), vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-oies)"]);

    // if we give a lon/lat near trifouilli-les-oies, we'll have another sort
    let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hector malot&lat=42.2&lon=24.0"));
    assert_eq!(get_labels(&all_20),
               vec!["20 Rue Hector Malot (Trifouilli-les-oies)", "20 Rue Hector Malot (Paris)"]);
    // and when we're in paris, we get paris first
    let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hector malot&lat=48&lon=3"));
    assert_eq!(get_labels(&all_20),
               vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-oies)"]);
}

fn get_labels<'a>(r: &'a Vec<BTreeMap<String, serde_json::Value>>) -> Vec<&'a str> {
    r.iter().map(|e| e.get("label").and_then(|l| l.as_string()).unwrap_or("")).collect()
}
<commit_msg>important rename<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate rustless;
extern crate iron;
extern crate iron_test;
extern crate serde_json;
use std::process::Command;
extern crate mime;
use std::collections::BTreeMap;

fn get_handler(url: String) -> rustless::Application {
    let api = bragi::api::ApiEndPoint { es_cnx_string: url }.root();
    rustless::Application::new(api)
}

pub fn bragi_tests(es_wrapper: ::ElasticSearchWrapper) {
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    let status = Command::new(bano2mimir)
                     .args(&["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())])
                     .status()
                     .unwrap();
    assert!(status.success(), "`bano2mimir` failed {}", &status);
    es_wrapper.refresh();

    let handler = get_handler(format!("{}/munin", es_wrapper.host()));

    let bragi_get = |q| {
        iron_test::request::get(&format!("http://localhost:3000{}", q),
                                iron::Headers::new(),
                                &handler)
            .unwrap()
    };
    let to_json = |r| -> serde_json::Value {
        let s = iron_test::response::extract_body_to_string(r);
        serde_json::from_str(&s).unwrap()
    };
    let get_results = |r| -> Vec<_> {
        to_json(r)
            .find("features")
            .expect("wrongly formated bragi response")
            .as_array()
            .expect("features must be array")
            .iter()
            .map(|f| {
                f.pointer("/properties/geocoding")
                 .expect("no geocoding object in bragi response")
                 .as_object()
                 .unwrap()
                 .clone()
            })
            .collect()
    };

    // Call status
    let resp = bragi_get("/status");
    let result_body = iron_test::response::extract_body_to_string(resp);

    assert_eq!(result_body,
               r#"{"version":"1.1.0","es":"http://localhost:9242/munin","status":"good"}"#);

    // Call autocomplete
    let resp = bragi_get("/autocomplete?q=15 Rue Hector Malot, (Paris)");
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":null,"#,
                         r#""city":null,"administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // A(48.846431 2.376488)
    // B(48.846430 2.376306)
    // C(48.846606 2.376309)
    // D(48.846603 2.376486)
    // R(48.846495 2.376378) : 15 Rue Hector Malot, (Paris)
    // E(48.846452 2.376580) : 18 Rue Hector Malot, (Paris)

    //             E
    //
    //      A ---------------------D
    //      |                      |
    //      |         R            |
    //      |                      |
    //      |                      |
    //      B ---------------------C
    // Search with shape where house number in shape
    let mut header = iron::Headers::new();
    let mime: mime::Mime = "application/json".parse().unwrap();
    header.set(iron::headers::ContentType(mime));
    let resp = iron_test::request::post("http://localhost:3000/autocomplete?q=15 Rue Hector \
                                        Malot, (Paris)",
                                       header.clone(),
                                       r#"{"geometry":{"type":"Polygon","coordinates":[[[48.846431,2.376488],[48.846430,2.376306],[48.846606,2.376309],[ 48.846603,2.376486]]]}}"#,
                                       &handler)
                   .unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.3763789999999996,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // Search with shape where house number out shape
    let resp = iron_test::request::post("http://localhost:3000/autocomplete?q=18 Rue Hector \
                                        Malot, (Paris)",
                                       header,
                                       r#"{"geometry":{"type":"Polygon","coordinates":[[[48.846431,2.376488],[48.846430,2.376306],[48.846606,2.376309],[ 48.846603,2.376486]]]}}"#,
                                       &handler)
                   .unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","geocoding":{"version":"0.1.0","query":""},"features":[]}"#);
    assert_eq!(result_body, result);

    // test with a lon/lat
    // in the dataset there are 2 '20 rue hector malot', one in paris and one in trifouilli-les-Oies
    // let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hect mal")); // in the mean time we time our prefix search_query
    // assert_eq!(all_20.len(), 2);
    // the first one is paris
    // TODO uncomment this test, for the moment since osm is not loaded, the order is random
    // assert_eq!(get_labels(&all_20), vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);

    // if we give a lon/lat near trifouilli-les-Oies, we'll have another sort
    let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hector malot&lat=42.2&lon=24.0"));
    assert_eq!(get_labels(&all_20),
               vec!["20 Rue Hector Malot (Trifouilli-les-Oies)", "20 Rue Hector Malot (Paris)"]);
    // and when we're in paris, we get paris first
    let all_20 = get_results(bragi_get("/autocomplete?q=20 rue hector malot&lat=48&lon=3"));
    assert_eq!(get_labels(&all_20),
               vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);
}

fn get_labels<'a>(r: &'a Vec<BTreeMap<String, serde_json::Value>>) -> Vec<&'a str> {
    r.iter().map(|e| e.get("label").and_then(|l| l.as_string()).unwrap_or("")).collect()
}
<|endoftext|>