<commit_before>use lapin_async::connection::*;
use lapin_async::api::ChannelState;
use lapin_async::format::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use std::io::{self,Error,ErrorKind,Read,Write};
use futures::{Async,AsyncSink,Poll,Sink,Stream,StartSend,Future};
use futures::future::{self, FutureResult,Loop};
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use tokio_core::io::{Codec,EasyBuf,Framed,Io};
use tokio_service::Service;
use tokio_proto::pipeline::{ClientProto, ClientService};
use tokio_proto::TcpClient;
use tokio_core::reactor::Handle;
use tokio_core::net::TcpStream;
use std::net::SocketAddr;
use std::thread;
use std::sync::{Arc,Mutex};

pub struct AMQPCodec;

impl Codec for AMQPCodec {
    type In = Frame;
    type Out = Frame;

    fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf.as_slice()) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.as_slice().offset(i), frame)
          }
        };

        println!("decoded frame: {:?}", f);
        buf.drain_to(consumed);
        Ok(Some(f))
    }

    fn encode(&mut self, frame: Frame, buf: &mut Vec<u8>) -> io::Result<()> {
      println!("buf capacity: {:?}", buf.capacity());
      if buf.len() < 8192 {
        buf.resize(8192, 0);
      }
      println!("buf len: {:?}", buf.len());
      println!("will send frame: {:?}", frame);
      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf.as_mut_slice(), 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf.as_mut_slice(), 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf.as_mut_slice(), 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf.as_mut_slice(), 0), channel_id, class_id, header.body_size).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf.as_mut_slice(), 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            println!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            println!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.resize(sz, 0);
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub conn: Connection<'static>,
}

impl<T> AMQPTransport<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
          T: 'static {
  pub fn connect(upstream: Framed<T,AMQPCodec>) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut t = AMQPTransport {
      upstream: upstream,
      conn:     Connection::new(),
    };

    t.conn.connect();
    let f = t.conn.next_frame().unwrap();
    t.upstream.start_send(f);
    t.upstream.poll_complete();
    t.upstream.get_mut().poll_read();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    println!("pre-poll");
    connector.poll();
    println!("post-poll");

    Box::new(connector)
  }

  pub fn send_frames(&mut self) {
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      //self.upstream.poll_complete();
    }
    self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    match self.poll() {
      Ok(Async::Ready(Some(frame))) => {
        println!("handle frames: AMQPTransport received frame: {:?}", frame);
        self.conn.handle_frame(frame);
      },
      Ok(Async::Ready(None)) => {
        println!("handle frames: upstream poll gave Ready(None)");
      },
      Ok(Async::NotReady) => {
        println!("handle frames: upstream poll gave NotReady");
        self.upstream.get_mut().poll_read();
      },
      Err(e) => {
        println!("handle frames: upstream poll got error: {:?}", e);
      },
    };
  }
}

pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error> {
          T : Io {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    println!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();
    println!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      println!("already connected");
      return Ok(Async::Ready(transport))
    }

    println!("waiting before poll");
    //thread::sleep_ms(2000);

    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        println!("upstream poll gave NotReady");
        thread::sleep_ms(100);
        //continue;
        transport.upstream.get_mut().poll_read();
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        println!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
    //match try_ready!(transport.upstream.poll()) {
      Some(frame) => {
        println!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        while let Some(f) = transport.conn.next_frame() {
          transport.upstream.start_send(f);
          transport.upstream.poll_complete();
        }
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        println!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
{
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        println!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              println!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              println!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
{
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        println!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        println!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

#[derive(Clone)]
pub struct Client {
    transport: Arc<Mutex<AMQPTransport<TcpStream>>>,
}

impl Client {
  pub fn connect(addr: &SocketAddr, handle: &Handle) -> Box<Future<Item = Client, Error = io::Error>> {
    let ret = TcpStream::connect(addr, handle)
      .and_then(|stream| {
        println!("will connect AMQPTransport");
        AMQPTransport::connect(stream.framed(AMQPCodec))
      }).and_then(|transport| {
        println!("got client service");

        //transport.connect();
        let mut client = Client {
          transport: Arc::new(Mutex::new(transport)),
        };

        future::ok(client)
      });

    Box::new(ret)
  }

  pub fn create_channel(&self) -> Box<Future<Item = Channel, Error = io::Error>> {
    let channel_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      let channel_id: u16 = transport.conn.create_channel();
      match transport.conn.channel_open(channel_id, "".to_string()) {
        //FIXME: should use errors from underlying library here
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not create channel")))
        ),
        Ok(request_id) => {
          println!("request id: {}", request_id);
          transport.send_frames();

          let channel = Channel {
            id:        channel_id,
            transport: channel_transport,
          };
          transport.handle_frames();

          Box::new(future::poll_fn(move || {
            println!("polling create_channel closure");
            let connected = if let Ok(mut tr) = channel.transport.try_lock() {
              println!("finished reqs: {:?}", tr.conn.finished_reqs);
              if ! tr.conn.is_finished(request_id) { // ! tr.conn.check_state(channel.id, ChannelState::Connected).unwrap_or(false) {
                //retry because we might have obtained a new frame
                println!("channel {} not connected before handle_frames", channel.id);
                tr.handle_frames();
                println!("finished reqs: {:?}", tr.conn.finished_reqs);
                let b = tr.conn.is_finished(request_id); //tr.conn.check_state(channel.id, ChannelState::Connected).unwrap_or(false);
                println!("channel {} openOk received? {} connected? {}", channel.id, b, tr.conn.check_state(channel.id, ChannelState::Connected).unwrap_or(false));
                b
              } else {
                println!("channel {} connected? {}", channel.id, true);
                true
              }
            } else {
              return Ok(Async::NotReady);
            };

            if connected {
              println!("create_channel closure returning ready");
              //FIXME: if we don't clone, we get the error 'cannot move out of captured outer variable in an `FnMut` closure'
              // if we clone, the previous temporary channel will be dropped at some point, right?
              Ok(Async::Ready(channel.clone()))
            } else {
              println!("create_channel closure returning not ready");
              Ok(Async::NotReady)
            }
          }))
        }
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

}

#[derive(Clone)]
pub struct Channel {
  pub transport: Arc<Mutex<AMQPTransport<TcpStream>>>,
  pub id:    u16,
}

impl Channel {
  pub fn declare_queue(&self, name: &str) -> Box<Future<Item = (), Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.queue_declare(self.id, 0, name.to_string(), false, false, false, false, false, HashMap::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not declare queue")))
        ),
        Ok(request_id) => {
          println!("queue_declare request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          println!("queue_declare returning closure");
          Box::new(future::poll_fn(move || {
            println!("polling queue_declare closure");
            let connected = if let Ok(mut tr) = cl_transport.try_lock() {
              println!("finished reqs: {:?}", tr.conn.finished_reqs);
              if ! tr.conn.is_finished(request_id) {
                //retry because we might have obtained a new frame
                tr.handle_frames();
                println!("finished reqs: {:?}", tr.conn.finished_reqs);
                tr.conn.is_finished(request_id)
              } else {
                true
              }
            } else {
              return Ok(Async::NotReady);
            };

            if connected {
              println!("queue_declare closure returning ready");
              Ok(Async::Ready(()))
            } else {
              println!("queue_declare closure returning not ready");
              Ok(Async::NotReady)
            }
          }))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }
}

<commit_msg>factor the request waiting code<commit_after>use lapin_async::connection::*;
use lapin_async::api::{ChannelState,RequestId};
use lapin_async::format::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use std::io::{self,Error,ErrorKind,Read,Write};
use futures::{Async,AsyncSink,Poll,Sink,Stream,StartSend,Future};
use futures::future::{self, FutureResult,Loop};
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use tokio_core::io::{Codec,EasyBuf,Framed,Io};
use tokio_service::Service;
use tokio_proto::pipeline::{ClientProto, ClientService};
use tokio_proto::TcpClient;
use tokio_core::reactor::Handle;
use tokio_core::net::TcpStream;
use std::net::SocketAddr;
use std::thread;
use std::sync::{Arc,Mutex};

pub struct AMQPCodec;

impl Codec for AMQPCodec {
    type In = Frame;
    type Out = Frame;

    fn decode(&mut self, buf: &mut EasyBuf) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf.as_slice()) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.as_slice().offset(i), frame)
          }
        };

        println!("decoded frame: {:?}", f);
        buf.drain_to(consumed);
        Ok(Some(f))
    }

    fn encode(&mut self, frame: Frame, buf: &mut Vec<u8>) -> io::Result<()> {
      println!("buf capacity: {:?}", buf.capacity());
      if buf.len() < 8192 {
        buf.resize(8192, 0);
      }
      println!("buf len: {:?}", buf.len());
      println!("will send frame: {:?}", frame);
      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf.as_mut_slice(), 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf.as_mut_slice(), 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf.as_mut_slice(), 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf.as_mut_slice(), 0), channel_id, class_id, header.body_size).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf.as_mut_slice(), 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            println!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            println!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.resize(sz, 0);
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub conn: Connection<'static>,
}

impl<T> AMQPTransport<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
          T: 'static {
  pub fn connect(upstream: Framed<T,AMQPCodec>) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut t = AMQPTransport {
      upstream: upstream,
      conn:     Connection::new(),
    };

    t.conn.connect();
    let f = t.conn.next_frame().unwrap();
    t.upstream.start_send(f);
    t.upstream.poll_complete();
    t.upstream.get_mut().poll_read();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    println!("pre-poll");
    connector.poll();
    println!("post-poll");

    Box::new(connector)
  }

  pub fn send_frames(&mut self) {
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      //self.upstream.poll_complete();
    }
    self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    match self.poll() {
      Ok(Async::Ready(Some(frame))) => {
        println!("handle frames: AMQPTransport received frame: {:?}", frame);
        self.conn.handle_frame(frame);
      },
      Ok(Async::Ready(None)) => {
        println!("handle frames: upstream poll gave Ready(None)");
      },
      Ok(Async::NotReady) => {
        println!("handle frames: upstream poll gave NotReady");
        self.upstream.get_mut().poll_read();
      },
      Err(e) => {
        println!("handle frames: upstream poll got error: {:?}", e);
      },
    };
  }
}

pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error> {
          T : Io {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    println!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();
    println!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      println!("already connected");
      return Ok(Async::Ready(transport))
    }

    println!("waiting before poll");
    //thread::sleep_ms(2000);

    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        println!("upstream poll gave NotReady");
        thread::sleep_ms(100);
        //continue;
        transport.upstream.get_mut().poll_read();
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        println!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
    //match try_ready!(transport.upstream.poll()) {
      Some(frame) => {
        println!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        while let Some(f) = transport.conn.next_frame() {
          transport.upstream.start_send(f);
          transport.upstream.poll_complete();
        }
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        println!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where //T: Stream<Item = Frame, Error = io::Error>,
          //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
{
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        println!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              println!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              println!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where //T: Sink<SinkItem = Frame, SinkError = io::Error>,
          T : Io,
{
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        println!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        println!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

#[derive(Clone)]
pub struct Client {
    transport: Arc<Mutex<AMQPTransport<TcpStream>>>,
}

impl Client {
  pub fn connect(addr: &SocketAddr, handle: &Handle) -> Box<Future<Item = Client, Error = io::Error>> {
    let ret = TcpStream::connect(addr, handle)
      .and_then(|stream| {
        println!("will connect AMQPTransport");
        AMQPTransport::connect(stream.framed(AMQPCodec))
      }).and_then(|transport| {
        println!("got client service");

        //transport.connect();
        let mut client = Client {
          transport: Arc::new(Mutex::new(transport)),
        };

        future::ok(client)
      });

    Box::new(ret)
  }

  pub fn create_channel(&self) -> Box<Future<Item = Channel, Error = io::Error>> {
    let channel_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      let channel_id: u16 = transport.conn.create_channel();
      match transport.conn.channel_open(channel_id, "".to_string()) {
        //FIXME: should use errors from underlying library here
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not create channel")))
        ),
        Ok(request_id) => {
          println!("request id: {}", request_id);
          transport.send_frames();
          transport.handle_frames();

          //FIXME: very afterwards that the state is Connected and not error
          Box::new(wait_for_answer(channel_transport.clone(), request_id).map(move |_| {
            Channel {
              id:        channel_id,
              transport: channel_transport,
            }
          }))
        }
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

}

#[derive(Clone)]
pub struct Channel {
  pub transport: Arc<Mutex<AMQPTransport<TcpStream>>>,
  pub id:    u16,
}

impl Channel {
  pub fn declare_queue(&self, name: &str) -> Box<Future<Item = (), Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.queue_declare(self.id, 0, name.to_string(), false, false, false, false, false, HashMap::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not declare queue")))
        ),
        Ok(request_id) => {
          println!("queue_declare request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          println!("queue_declare returning closure");
          wait_for_answer(cl_transport, request_id)
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }
}

pub fn wait_for_answer(transport: Arc<Mutex<AMQPTransport<TcpStream>>>, request_id: RequestId) -> Box<Future<Item = (), Error = io::Error>> {
  Box::new(future::poll_fn(move || {
    //println!("polling queue_declare closure");
    let connected = if let Ok(mut tr) = transport.try_lock() {
      println!("finished reqs: {:?}", tr.conn.finished_reqs);
      if ! tr.conn.is_finished(request_id) {
        //retry because we might have obtained a new frame
        tr.handle_frames();
        println!("finished reqs: {:?}", tr.conn.finished_reqs);
        tr.conn.is_finished(request_id)
      } else {
        true
      }
    } else {
      return Ok(Async::NotReady);
    };

    if connected {
      //println!("queue_declare closure returning ready");
      Ok(Async::Ready(()))
    } else {
      //println!("queue_declare closure returning not ready");
      Ok(Async::NotReady)
    }
  }))

}
<|endoftext|>


<commit_before>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

#[derive(Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
    Pending,
    Done,
    Error,
}

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,

    status: JobStatus,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<Job>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("mp4"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            self.jobs.push(Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
                status: JobStatus::Pending,
            });
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn run(&mut self) {
        let pending_jobs = self.jobs
            .iter_mut()
            .filter(|j| j.status == JobStatus::Pending)
            .collect::<Vec<&mut Job>>();

        println!("{} pending jobs", pending_jobs.len());

        for job in pending_jobs {
            let path = Path::new(job.source_path.as_str());
            let sub_path = match path.strip_prefix(self.source_dir.as_str()) {
                Ok(sp) => sp,
                Err(e) => {
                    println!("   Could not get sub-path: {}", e);
                    job.status = JobStatus::Error;
                    continue;
                }
            };

            println!("Processing: {:?}", sub_path);

            if !path.exists() {
                job.status = JobStatus::Error;
                println!("   Path does not exist");
                continue;
            } else if !path.is_file() {
                job.status = JobStatus::Error;
                println!("   Path is not a file");
                continue;
            }

            let extension = match path.extension() {
                Some(e) => match e.to_str() {
                    Some(es) => es,
                    None => {
                        job.status = JobStatus::Error;
                        println!("   Error converting to string");
                        continue;
                    }
                },
                None => {
                    job.status = JobStatus::Done;
                    println!("   No extension");
                    continue;
                }
            };

            let rule = match self.rules.get(extension) {
                Some(r) => r,
                None => {
                    job.status = JobStatus::Done;
                    println!("   No rule defined for extension '{}'", extension);
                    continue;
                }
            };

            let args: Vec<&str> = rule.split_whitespace().collect();
            println!("   {:?}", args);

            let out_path = Path::new(self.destination_dir.as_str()).join(sub_path);
            println!("   Writting to {:?}", out_path);

            job.status = JobStatus::Done;
        }
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }
        Ok(())
    }

    fn convert_video(&self, source_filepath: &Path, output_dir: &str) {
        let mut out_file = PathBuf::new();
        out_file.push(output_dir);
        out_file.push(source_filepath.file_stem().unwrap());
        out_file.set_extension("mp4");

        let mut output = Command::new("ffmpeg")
            .arg("-loglevel")
            .arg("warning")
            .arg("-i")
            .arg(source_filepath)
            .arg("-y")
            .arg("-c:v")
            .arg("libx264")
            .arg("-preset")
            .arg("ultrafast")
            .arg("-framerate")
            .arg("30")
            .arg("-vsync")
            .arg("1")
            .arg("-crf")
            .arg("20")
            .arg(out_file.as_path())
            .spawn()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        output.wait().unwrap();
    }
}
<commit_msg>Cleanup<commit_after>extern crate serde_json;

use sha2::{Digest, Sha256};
use std::cell::RefCell;
use std::collections::HashMap;
use std::error::Error;
use std::fs::{self, DirEntry, File};
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;

#[derive(Serialize, Deserialize, PartialEq)]
pub enum JobStatus {
    Pending,
    Done,
    Error,
}

#[derive(Serialize, Deserialize)]
pub struct Job {
    source_path: String,
    source_sha256sum: String,
    destination_path: String,
    destination_sha256sum: String,

    status: JobStatus,
}

#[derive(Serialize, Deserialize)]
pub struct BatchJob {
    source_dir: String,
    destination_dir: String,
    rules: HashMap<String, String>,
    jobs: Vec<RefCell<Job>>,
}

impl BatchJob {
    pub fn new(source_dir: String, destination_dir: String) -> BatchJob {
        let mut bj = BatchJob {
            source_dir: source_dir,
            destination_dir: destination_dir,
            rules: HashMap::new(),
            jobs: vec![],
        };

        bj.rules.insert(
            String::from("mp4"),
            String::from("ffmpeg -i $file_path -c:v libx264 -preset slow"),
        );

        bj
    }

    pub fn init(&mut self) -> Result<(), Box<Error>> {
        let mut lst = vec![];

        // flatten
        {
            let mut add_it = |x: &DirEntry| {
                lst.push(x.path());
            };

            self.visit_dirs(Path::new(&self.source_dir.trim()), &mut add_it)?;
        }

        println!("scanned {} files", lst.len());

        for file in lst.iter() {
            let source_path = file.to_str().unwrap();
            println!("processing {}", source_path);
            let mut file = File::open(source_path).expect("Unable to create config file");
            let hash = Sha256::digest_reader(&mut file)?;

            let job = Job {
                source_path: String::from(source_path),
                source_sha256sum: String::from(format!("{:x}", hash)),
                destination_path: String::new(),
                destination_sha256sum: String::new(),
                status: JobStatus::Pending,
            };

            self.jobs.push(RefCell::new(job));
        }

        Ok(())
    }

    pub fn load_from_file(dir: &str) -> Result<BatchJob, Box<Error>> {
        let filepath = format!("{}/dbfc.config", dir);
        let mut file = File::open(filepath)?;
        let mut buffer = String::new();
        file.read_to_string(&mut buffer)?;
        let bj: BatchJob = serde_json::from_str(&buffer)?;

        Ok(bj)
    }

    pub fn run(&mut self) {
        let pending_jobs = self.jobs
            .iter()
            .filter(|j| j.borrow().status == JobStatus::Pending)
            .collect::<Vec<&RefCell<Job>>>();

        println!("{} pending jobs", pending_jobs.len());

        for job_ref in pending_jobs {
            let mut job = job_ref.borrow_mut();

            match self.run_job(&job, self.source_dir.as_str()) {
                Ok(_) => {
                    job.status = JobStatus::Done;
                }
                Err(why) => {
                    job.status = JobStatus::Error;
                    println!("   {}", why);
                }
            }
        }
    }

    fn run_job(&self, job: &Job, source_dir: &str) -> Result<(), String> {
        let path = Path::new(job.source_path.as_str());
        let sub_path = match path.strip_prefix(source_dir) {
            Ok(sp) => sp,
            Err(e) => {
                return Err(format!("   Could not get sub-path: {}", e));
            }
        };

        println!("Processing: {:?}", sub_path);

        if !path.exists() {
            return Err(format!("   Path does not exist"));
        } else if !path.is_file() {
            return Err(format!("   Path is not a file"));
        }

        let extension = match path.extension() {
            Some(e) => match e.to_str() {
                Some(es) => es,
                None => {
                    return Err(format!("   Error converting to string"));
                }
            },
            None => {
                return Err(format!("   No extension"));
            }
        };

        let rule = match self.rules.get(extension) {
            Some(r) => r,
            None => {
                return Err(format!("   No rule defined for extension '{}'", extension));
            }
        };

        let args: Vec<&str> = rule.split_whitespace().collect();
        println!("   {:?}", args);

        let out_path = Path::new(self.destination_dir.as_str()).join(sub_path);
        println!("   Writting to {:?}", out_path);

        Ok(())
    }

    fn visit_dirs(&self, dir: &Path, cb: &mut FnMut(&DirEntry)) -> Result<(), Box<Error>> {
        if dir.is_dir() {
            for entry in fs::read_dir(dir)? {
                let entry = entry?;
                let path = entry.path();
                if path.is_dir() {
                    self.visit_dirs(&path, cb)?;
                } else {
                    cb(&entry);
                }
            }
        }
        Ok(())
    }

    fn convert_video(&self, source_filepath: &Path, output_dir: &str) {
        let mut out_file = PathBuf::new();
        out_file.push(output_dir);
        out_file.push(source_filepath.file_stem().unwrap());
        out_file.set_extension("mp4");

        let mut output = Command::new("ffmpeg")
            .arg("-loglevel")
            .arg("warning")
            .arg("-i")
            .arg(source_filepath)
            .arg("-y")
            .arg("-c:v")
            .arg("libx264")
            .arg("-preset")
            .arg("ultrafast")
            .arg("-framerate")
            .arg("30")
            .arg("-vsync")
            .arg("1")
            .arg("-crf")
            .arg("20")
            .arg(out_file.as_path())
            .spawn()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        output.wait().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate clap;

#[macro_use]
extern crate futures;
extern crate futures_cpupool;

#[macro_use]
extern crate tokio_core;

use futures::{Async, Poll, Future};

use byteorder::{LittleEndian, ByteOrder};

use std::cell::{Cell};
use std::rc::Rc;

mod all {
    use futures::{Async, Poll, Future};
    enum ElemState<T> where T: Future {
        Pending(T),
        Done(T::Item),
    }

    pub struct All<T> where T: Future {
        elems: Vec<ElemState<T>>,
    }

    impl <T> All<T> where T: Future {
        pub fn new<I>(futures: I) -> All<T> where I: Iterator<Item=T> {
            let mut result = All { elems: Vec::new() };
            for f in futures {
                result.elems.push(ElemState::Pending(f))
            }
            result
        }
    }

    impl <T> Future for All<T> where T: Future {
        type Item = Vec<T::Item>;
        type Error = T::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            let mut all_done = true;

            for idx in 0 .. self.elems.len() {
                let done_val = match &mut self.elems[idx] {
                    &mut ElemState::Pending(ref mut t) => {
                        match t.poll() {
                            Ok(Async::Ready(t)) => t,
                            Ok(Async::NotReady) => {
                                all_done = false;
                                continue
                            }
                            Err(e) => return Err(e),
                        }
                    }
                    &mut ElemState::Done(ref mut _v) => continue,
                };

                self.elems[idx] = ElemState::Done(done_val);
            }

            if all_done {
                let mut result = Vec::new();
                let elems = ::std::mem::replace(&mut self.elems, Vec::new());
                for e in elems.into_iter() {
                    match e {
                        ElemState::Done(t) => result.push(t),
                        _ => unreachable!(),
                    }
                }
                Ok(Async::Ready(result))
            } else {
                Ok(Async::NotReady)
            }
        }
    }
}

struct Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    f: F,
    in_progress: T,
}

fn tie_knot<F, S, T, E>(initial_state: S, f: F) -> Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>,
{
    let in_progress = f(initial_state);
    Knot {
        f: f,
        in_progress: in_progress,
    }
}

impl <F, S, T, E> Future for Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    type Item = S;
    type Error = E;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let (s, more) = try_ready!(self.in_progress.poll());
            if more {
                self.in_progress = (self.f)(s);
            } else {
                return Ok(Async::Ready(s))
            }
        }
    }
}

struct Reading<R> where R: ::std::io::Read {
    reader: Option<R>,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> Reading<R> where R: ::std::io::Read {
    fn new(reader: R) -> Reading<R> {
        Reading {
            reader: Some(reader),
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Future for Reading<R> where R: ::std::io::Read {
    type Item = (R, Option<Vec<u8>>);
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    self.frame_end = None;
                    return Ok(Async::Ready((self.reader.take().unwrap(), Some(result))))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready((self.reader.take().unwrap(), None)))
                }
                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub struct Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    writer: Option<W>,
    message: B,
    pos: usize,
    wrote_header: bool,
}

impl <W, B> Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    fn new(writer: W, message: B) -> Writing<W, B> {
        Writing {
            writer: Some(writer),
            message: message,
            pos: 0,
            wrote_header: false,
        }
    }
}

impl <W, B> Future for Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    type Item = W;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if !self.wrote_header {
                let buf = [self.message.as_ref().len() as u8];
                try_nb!(self.writer.as_mut().unwrap().write(&buf));
                self.wrote_header = true;
            } else {
                let n = try_nb!(self.writer.as_mut().unwrap().write(&self.message.as_ref()[self.pos..]));
                self.pos += n;
                if self.pos >= self.message.as_ref().len() {
                    return Ok(Async::Ready(self.writer.take().unwrap()))
                }
            }
        }
    }
}

#[derive(Clone)]
struct ConnectionIdSource {
    next_id: Rc<Cell<u64>>,
}

impl ConnectionIdSource {
    fn new() -> ConnectionIdSource {
        ConnectionIdSource {
            next_id: Rc::new(Cell::new(0)),
        }
    }

    fn next(&self) -> u64 {
        let result = self.next_id.get();
        self.next_id.set(result + 1);
        result
    }
}

fn read_until_message_with_prefix<R, B>(
    reader: R,
    prefix: B)
    -> Box<Future<Item=(R, Vec<u8>), Error=::std::io::Error> + 'static + Send>
    where R: ::std::io::Read + 'static + Send,
          B: AsRef<[u8]> + 'static + Send,
{
    Box::new(tie_knot((reader, prefix, Vec::new()), move |(reader, prefix, _)| {
        Reading::new(reader).and_then(move |(reader, message)| {
            match message {
                Some(message) => {
                    let len = prefix.as_ref().len();
                    let more = &message[0..len] != prefix.as_ref();
                    Ok(((reader, prefix, message), more))
                }
                None => {
                    Err(::std::io::Error::new(
                        ::std::io::ErrorKind::UnexpectedEof, "premature EOF"))
                }
            }
        })
    }).map(|(reader, _, message)| (reader, message)))
}

fn new_task(handle: &::tokio_core::reactor::Handle,
            addr: &::std::net::SocketAddr,
            connection_id_source: ConnectionIdSource)
            -> Box<Future<Item=(), Error=::std::io::Error> + Send>
{
    use all::All;

    let publisher = ::tokio_core::net::TcpStream::connect(addr, handle);
    let _publisher_id = connection_id_source.next();

    let mut subscribers = Vec::new();
    for _ in 0..1 {
        let subscriber_id = connection_id_source.next();
        subscribers.push(::tokio_core::net::TcpStream::connect(addr, handle).and_then(move |socket| {
            let mut buf = [0; 8];
            <LittleEndian as ByteOrder>::write_u64(&mut buf[..], subscriber_id);
            Writing::new(socket, buf).and_then(move |socket| {
                read_until_message_with_prefix(socket, buf).map(|(socket, _message)| {
                    socket
                })
            })
        }))
    }

    Box::new(publisher.join(All::new(subscribers.into_iter())).and_then(|(publisher, subscribers)| {
        tie_knot((publisher, subscribers, 10i32), |(publisher, subscribers, n)| {
            println!("looping {}", n);
            Writing::new(publisher, vec![n as u8, 1,2,3]).and_then(move |publisher| {
                All::new(subscribers.into_iter().map(|s| {
                    Reading::new(s).and_then(|(s, m)| {
                        println!("got: {:?}", m);
                        Ok(s)
                    })
                })).and_then(move |subscribers| {
                    futures::finished(((publisher, subscribers, n - 1), n > 0))
                })
            })
        }).map(|_| ())
    }))
}

struct ChildProcess {
    child: ::std::process::Child
}

impl ChildProcess {
    fn new(child: ::std::process::Child) -> ChildProcess {
        ChildProcess { child: child }
    }
}

impl Drop for ChildProcess {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

pub fn run() -> Result<(), ::std::io::Error> {
    use clap::{App, Arg};
    let matches = App::new("Zillions benchmarker")
        .version("0.0.0")
        .about("Does awesome things")
        .arg(Arg::with_name("EXECUTABLE")
             .required(true)
             .index(1)
             .help("The executable to benchmark"))
        .arg(Arg::with_name("server")
             .required(false)
             .long("server")
             .short("s")
             .value_name("address")
             .default_value("127.0.0.1:8080")
             .help("address to use to connect to server"))
        .get_matches();

    let executable = matches.value_of("EXECUTABLE").unwrap();

    println!("exectuable: {}", executable);

    let addr_str = matches.value_of("server").unwrap();
    let addr = match addr_str.parse::<::std::net::SocketAddr>() {
        Ok(a) => a,
        Err(e) => {
            panic!("failed to parse socket address {}", e);
        }
    };

    let mut child = try!(::std::process::Command::new(executable)
        .arg(addr_str)
        .stdout(::std::process::Stdio::piped())
        .stderr(::std::process::Stdio::inherit())
        .spawn());

    let mut child_stdout = ::std::io::BufReader::new(child.stdout.take().unwrap());
    let _wrapped_child = ChildProcess::new(child);

    let mut first_line = String::new();
    try!(::std::io::BufRead::read_line(&mut child_stdout, &mut first_line));

    if !first_line.starts_with("listening on") {
        return Err(::std::io::Error::new(
            ::std::io::ErrorKind::Other,
            format!(
                "expected first line from server to start with 'listening on ', but got {}",
                first_line)))
    }

    // start tokio reactor
    let mut core = try!(::tokio_core::reactor::Core::new());

    let handle = core.handle();

    let pool = ::futures_cpupool::CpuPool::new_num_cpus();

    let connection_id_source = ConnectionIdSource::new();

    let f = pool.spawn(new_task(&handle, &addr, connection_id_source));

    try!(core.run(f));

    Ok(())
}

pub fn main() {
    run().expect("top level error");
}
<commit_msg>write and read connection ids<commit_after>extern crate byteorder;
extern crate clap;

#[macro_use]
extern crate futures;
extern crate futures_cpupool;

#[macro_use]
extern crate tokio_core;

use futures::{Async, Poll, Future};

use byteorder::{LittleEndian, ByteOrder};

use std::cell::{Cell};
use std::rc::Rc;

mod all {
    use futures::{Async, Poll, Future};
    enum ElemState<T> where T: Future {
        Pending(T),
        Done(T::Item),
    }

    pub struct All<T> where T: Future {
        elems: Vec<ElemState<T>>,
    }

    impl <T> All<T> where T: Future {
        pub fn new<I>(futures: I) -> All<T> where I: Iterator<Item=T> {
            let mut result = All { elems: Vec::new() };
            for f in futures {
                result.elems.push(ElemState::Pending(f))
            }
            result
        }
    }

    impl <T> Future for All<T> where T: Future {
        type Item = Vec<T::Item>;
        type Error = T::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            let mut all_done = true;

            for idx in 0 .. self.elems.len() {
                let done_val = match &mut self.elems[idx] {
                    &mut ElemState::Pending(ref mut t) => {
                        match t.poll() {
                            Ok(Async::Ready(t)) => t,
                            Ok(Async::NotReady) => {
                                all_done = false;
                                continue
                            }
                            Err(e) => return Err(e),
                        }
                    }
                    &mut ElemState::Done(ref mut _v) => continue,
                };

                self.elems[idx] = ElemState::Done(done_val);
            }

            if all_done {
                let mut result = Vec::new();
                let elems = ::std::mem::replace(&mut self.elems, Vec::new());
                for e in elems.into_iter() {
                    match e {
                        ElemState::Done(t) => result.push(t),
                        _ => unreachable!(),
                    }
                }
                Ok(Async::Ready(result))
            } else {
                Ok(Async::NotReady)
            }
        }
    }
}

struct Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    f: F,
    in_progress: T,
}

fn tie_knot<F, S, T, E>(initial_state: S, f: F) -> Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>,
{
    let in_progress = f(initial_state);
    Knot {
        f: f,
        in_progress: in_progress,
    }
}

impl <F, S, T, E> Future for Knot<F, S, T, E>
    where F: Fn(S) -> T,
          T: Future<Item=(S, bool), Error=E>
{
    type Item = S;
    type Error = E;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            let (s, more) = try_ready!(self.in_progress.poll());
            if more {
                self.in_progress = (self.f)(s);
            } else {
                return Ok(Async::Ready(s))
            }
        }
    }
}

struct Reading<R> where R: ::std::io::Read {
    reader: Option<R>,
    buffer: Vec<u8>,
    pos: usize,
    frame_end: Option<u8>,
}

impl <R> Reading<R> where R: ::std::io::Read {
    fn new(reader: R) -> Reading<R> {
        Reading {
            reader: Some(reader),
            buffer: Vec::new(),
            pos: 0,
            frame_end: None,
        }
    }
}

impl <R> Future for Reading<R> where R: ::std::io::Read {
    type Item = (R, Option<Vec<u8>>);
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if let Some(frame_end) = self.frame_end {
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut self.buffer[self.pos..frame_end as usize]));
                self.pos += n;
                if self.pos == frame_end as usize {
                    self.pos = 0;
                    let result = ::std::mem::replace(&mut self.buffer, Vec::new());
                    self.frame_end = None;
                    return Ok(Async::Ready((self.reader.take().unwrap(), Some(result))))
                }
            } else {
                let mut buf = [0u8];
                let n = try_nb!(self.reader.as_mut().unwrap().read(&mut buf));
                if n == 0 { // EOF
                    return Ok(Async::Ready((self.reader.take().unwrap(), None)))
                }
                self.frame_end = Some(buf[0]);
                self.buffer = vec![0; buf[0] as usize];
            }
        }
    }
}

pub struct Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    writer: Option<W>,
    message: B,
    pos: usize,
    wrote_header: bool,
}

impl <W, B> Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    fn new(writer: W, message: B) -> Writing<W, B> {
        Writing {
            writer: Some(writer),
            message: message,
            pos: 0,
            wrote_header: false,
        }
    }
}

impl <W, B> Future for Writing<W, B> where W: ::std::io::Write, B: AsRef<[u8]> {
    type Item = W;
    type Error = ::std::io::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        loop {
            if !self.wrote_header {
                let buf = [self.message.as_ref().len() as u8];
                try_nb!(self.writer.as_mut().unwrap().write(&buf));
                self.wrote_header = true;
            } else {
                let n = try_nb!(self.writer.as_mut().unwrap().write(&self.message.as_ref()[self.pos..]));
                self.pos += n;
                if self.pos >= self.message.as_ref().len() {
                    return Ok(Async::Ready(self.writer.take().unwrap()))
                }
            }
        }
    }
}

#[derive(Clone)]
struct ConnectionIdSource {
    next_id: Rc<Cell<u64>>,
}

impl ConnectionIdSource {
    fn new() -> ConnectionIdSource {
        ConnectionIdSource {
            next_id: Rc::new(Cell::new(0)),
        }
    }

    fn next(&self) -> u64 {
        let result = self.next_id.get();
        self.next_id.set(result + 1);
        result
    }
}

fn read_until_message_with_prefix<R, B>(
    reader: R,
    prefix: B)
    -> Box<Future<Item=(R, Vec<u8>), Error=::std::io::Error> + 'static + Send>
    where R: ::std::io::Read + 'static + Send,
          B: AsRef<[u8]> + 'static + Send,
{
    Box::new(tie_knot((reader, prefix, Vec::new()), move |(reader, prefix, _)| {
        Reading::new(reader).and_then(move |(reader, message)| {
            match message {
                Some(message) => {
                    let len = prefix.as_ref().len();
                    let more = &message[0..len] != prefix.as_ref();
                    Ok(((reader, prefix, message), more))
                }
                None => {
                    Err(::std::io::Error::new(
                        ::std::io::ErrorKind::UnexpectedEof, "premature EOF"))
                }
            }
        })
    }).map(|(reader, _, message)| (reader, message)))
}

fn new_task(handle: &::tokio_core::reactor::Handle,
            addr: &::std::net::SocketAddr,
            connection_id_source: ConnectionIdSource,
            number_of_messages: u64)
            -> Box<Future<Item=(), Error=::std::io::Error> + Send>
{
    use all::All;

    let publisher = ::tokio_core::net::TcpStream::connect(addr, handle);
    let publisher_id = connection_id_source.next();

    let mut subscribers = Vec::new();
    for _ in 0..1 {
        let subscriber_id = connection_id_source.next();
        subscribers.push(::tokio_core::net::TcpStream::connect(addr, handle).and_then(move |socket| {
            let mut buf = [0; 8];
            <LittleEndian as ByteOrder>::write_u64(&mut buf[..], subscriber_id);
            Writing::new(socket, buf).and_then(move |socket| {
                read_until_message_with_prefix(socket, buf).map(|(socket, _message)| {
                    socket
                })
            })
        }))
    }

    Box::new(publisher.join(All::new(subscribers.into_iter())).and_then(move |(publisher, subscribers)| {
        tie_knot((publisher, subscribers, 0u64), move |(publisher, subscribers, n)| {
            println!("looping {}", n);
            let mut buf = vec![255; 16];
            let mut prefix = [0; 8];
            <LittleEndian as ByteOrder>::write_u64(&mut buf[..8], publisher_id);
            <LittleEndian as ByteOrder>::write_u64(&mut prefix[..], publisher_id);

            Writing::new(publisher, buf).and_then(move |publisher| {
                All::new(subscribers.into_iter().map(move |s| {
                    read_until_message_with_prefix(s, prefix).map(|(s, message)| {
                        println!("got: {:?}", message);
                        s
                    })
                })).and_then(move |subscribers| {
                    futures::finished(((publisher, subscribers, n + 1), n < number_of_messages))
                })
            })
        }).map(|_| ())
    }))
}

struct ChildProcess {
    child: ::std::process::Child
}

impl ChildProcess {
    fn new(child: ::std::process::Child) -> ChildProcess {
        ChildProcess { child: child }
    }
}

impl Drop for ChildProcess {
    fn drop(&mut self) {
        let _ = self.child.kill();
    }
}

pub fn run() -> Result<(), ::std::io::Error> {
    use clap::{App, Arg};
    let matches = App::new("Zillions benchmarker")
        .version("0.0.0")
        .about("Does awesome things")
        .arg(Arg::with_name("EXECUTABLE")
             .required(true)
             .index(1)
             .help("The executable to benchmark"))
        .arg(Arg::with_name("server")
             .required(false)
             .long("server")
             .short("s")
             .value_name("address")
             .default_value("127.0.0.1:8080")
             .help("address to use to connect to server"))
        .get_matches();

    let executable = matches.value_of("EXECUTABLE").unwrap();

    println!("exectuable: {}", executable);

    let addr_str = matches.value_of("server").unwrap();
    let addr = match addr_str.parse::<::std::net::SocketAddr>() {
        Ok(a) => a,
        Err(e) => {
            panic!("failed to parse socket address {}", e);
        }
    };

    let mut child = try!(::std::process::Command::new(executable)
        .arg(addr_str)
        .stdout(::std::process::Stdio::piped())
        .stderr(::std::process::Stdio::inherit())
        .spawn());

    let mut child_stdout = ::std::io::BufReader::new(child.stdout.take().unwrap());
    let _wrapped_child = ChildProcess::new(child);

    let mut first_line = String::new();
    try!(::std::io::BufRead::read_line(&mut child_stdout, &mut first_line));

    if !first_line.starts_with("listening on") {
        return Err(::std::io::Error::new(
            ::std::io::ErrorKind::Other,
            format!(
                "expected first line from server to start with 'listening on ', but got {}",
                first_line)))
    }

    // start tokio reactor
    let mut core = try!(::tokio_core::reactor::Core::new());

    let handle = core.handle();

    let pool = ::futures_cpupool::CpuPool::new_num_cpus();

    let connection_id_source = ConnectionIdSource::new();

    let f = pool.spawn(new_task(&handle, &addr, connection_id_source.clone(), 5)
                       .join(new_task(&core.handle(), &addr, connection_id_source, 5)));

    try!(core.run(f));

    Ok(())
}

pub fn main() {
    run().expect("top level error");
}
<|endoftext|>


<commit_before>// Lumol, an extensible molecular simulation engine
// Copyright (C) Lumol's contributors — BSD license
extern crate lumol;
extern crate lumol_input;

#[macro_use]
extern crate log;
extern crate clap;
extern crate chrono;

use lumol_input::Input;
use clap::{App, ArgMatches};
use chrono::offset::Local;
use chrono::Duration;

fn parse_args<'a>() -> ArgMatches<'a> {
    App::new("lumol")
        .version(lumol::VERSION)
        .about("An extensible molecular simulation engine")
        .args_from_usage("<input.toml>      'Simulation input file'")
        .get_matches()
}

fn main() {
    let args = parse_args();
    let input = args.value_of("input.toml").unwrap();
    let mut config = match Input::new(input).and_then(|input| input.read()) {
        Ok(config) => config,
        Err(err) => {
            error!("bad input file: {}", err);
            std::process::exit(2)
        }
    };

    info!("Running lumol version {}", lumol::VERSION);

    let start = Local::now();
    info!("Simulation started the {} at {}", start.format("%Y-%m-%d"), start.format("%H:%M:%S"));
    config.simulation.run(&mut config.system, config.nsteps);

    let end = Local::now();
    info!("Simulation ended the {} at {}", end.format("%Y-%m-%d"), end.format("%H:%M:%S"));
    let elapsed = end.signed_duration_since(start);
    info!("Simulation ran for {}", format_elapsed(elapsed));
}

fn format_elapsed(elapsed: Duration) -> String {
    if elapsed.num_weeks() > 0 {
        let h = elapsed.num_hours() % 24;
        let d = elapsed.num_days() % 7;
        let w = elapsed.num_weeks();
        format!("{} weeks {} days {}h", w, d, h)
    } else if elapsed.num_days() > 0 {
        let m = elapsed.num_minutes() % 60;
        let h = elapsed.num_hours() % 24;
        let d = elapsed.num_days();
        format!("{} days {}h {}min", d, h, m)
    } else if elapsed.num_hours() > 0 {
        let s = elapsed.num_seconds() % 60;
        let m = elapsed.num_minutes() % 60;
        let h = elapsed.num_hours();
        format!("{}h {}min {}s", h, m, s)
    } else {
        let s = elapsed.num_seconds() % 60;
        let m = elapsed.num_minutes();
        format!("{}min {}s", m, s)
    }
}
<commit_msg>Skip some lines in the output<commit_after>// Lumol, an extensible molecular simulation engine
// Copyright (C) Lumol's contributors — BSD license
extern crate lumol;
extern crate lumol_input;

#[macro_use]
extern crate log;
extern crate clap;
extern crate chrono;

use lumol_input::Input;
use clap::{App, ArgMatches};
use chrono::offset::Local;
use chrono::Duration;

fn parse_args<'a>() -> ArgMatches<'a> {
    App::new("lumol")
        .version(lumol::VERSION)
        .about("An extensible molecular simulation engine")
        .args_from_usage("<input.toml>      'Simulation input file'")
        .get_matches()
}

fn main() {
    let args = parse_args();
    let input = args.value_of("input.toml").unwrap();
    let mut config = match Input::new(input).and_then(|input| input.read()) {
        Ok(config) => config,
        Err(err) => {
            error!("bad input file: {}", err);
            std::process::exit(2)
        }
    };

    info!("Running lumol version {}", lumol::VERSION);

    let start = Local::now();
    info!("Simulation started the {} at {}", start.format("%Y-%m-%d"), start.format("%H:%M:%S"));
    info!(" "); // Skip a line

    config.simulation.run(&mut config.system, config.nsteps);

    let end = Local::now();
    info!("\nSimulation ended the {} at {}", end.format("%Y-%m-%d"), end.format("%H:%M:%S"));
    let elapsed = end.signed_duration_since(start);
    info!("Simulation ran for {}", format_elapsed(elapsed));
}

fn format_elapsed(elapsed: Duration) -> String {
    if elapsed.num_weeks() > 0 {
        let h = elapsed.num_hours() % 24;
        let d = elapsed.num_days() % 7;
        let w = elapsed.num_weeks();
        format!("{} weeks {} days {}h", w, d, h)
    } else if elapsed.num_days() > 0 {
        let m = elapsed.num_minutes() % 60;
        let h = elapsed.num_hours() % 24;
        let d = elapsed.num_days();
        format!("{} days {}h {}min", d, h, m)
    } else if elapsed.num_hours() > 0 {
        let s = elapsed.num_seconds() % 60;
        let m = elapsed.num_minutes() % 60;
        let h = elapsed.num_hours();
        format!("{}h {}min {}s", h, m, s)
    } else {
        let s = elapsed.num_seconds() % 60;
        let m = elapsed.num_minutes();
        format!("{}min {}s", m, s)
    }
}
<|endoftext|>


<commit_before>mod error;

use router::Router;
use iron::prelude::*;
use iron::status;
use iron::mime::{Mime, TopLevel, SubLevel};
use params::{Params, Value};
use params;
use chrono::UTC;

use exonum::crypto::{Hash, HexValue, Signature};
use exonum::blockchain::Blockchain;
use exonum::node::TransactionSend;
use exonum::api::Api;
use exonum::storage::MapProof;

use {TimestampTx, TimestampingSchema, Content};
pub use self::error::Error as ApiError;

#[derive(Clone)]
pub struct PublicApi<T: TransactionSend + Clone> {
    channel: T,
    blockchain: Blockchain,
}

impl<T> PublicApi<T>
where
    T: TransactionSend + Clone,
{
    pub fn new(blockchain: Blockchain, channel: T) -> PublicApi<T> {
        PublicApi {
            blockchain: blockchain,
            channel: channel,
        }
    }

    fn put_content(&self, hash_str: &str, description: &str) -> Result<TimestampTx, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let snapshot = self.blockchain.snapshot();

        if TimestampingSchema::new(&snapshot)
            .contents()
            .get(&hash)
            .is_some()
        {
            return Err(ApiError::FileExists(hash));
        }
        // Create transaction
        let ts = UTC::now().timestamp();
        let tx = TimestampTx::new_with_signature(&description, ts, &hash, &Signature::zero());
        self.channel.send(Box::new(tx.clone()))?;
        Ok(tx)
    }

    fn get_content(&self, hash_str: &str) -> Result<Content, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let view = self.blockchain.snapshot();
        TimestampingSchema::new(&view)
            .contents()
            .get(&hash)
            .ok_or_else(|| ApiError::FileNotFound(hash))
    }

    fn get_proof(&self, hash_str: &str) -> Result<MapProof<Content>, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let view = self.blockchain.snapshot();
        let schema = TimestampingSchema::new(&view);
        Ok(schema.contents().get_proof(&hash))
    }
}

impl<T> Api for PublicApi<T>
where
    T: TransactionSend + Clone + 'static,
{
    // FIXME Rewrite without unwrap and boiler-plate code
    fn wire(&self, router: &mut Router) {
        // Receive a message by POST and play it back.
        let api = self.clone();
        let put_content = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();

            fn find_str<'a>(map: &'a params::Map, path: &[&str]) -> Result<&'a str, ApiError> {
                let value = map.find(path);
                if let Some(&Value::String(ref s)) = value {
                    Ok(s)
                } else {
                    Err(ApiError::IncorrectRequest)
                }
            };

            let hash = find_str(map, &["hash"])?;
            let description = find_str(map, &["description"]).unwrap_or("");

            let tx = api.put_content(hash, description)?;
            let content_type = Mime(TopLevel::Application, SubLevel::Json, Vec::new());
            let response = Response::with((content_type, status::Ok, json!(tx).to_string()));
            return Ok(response);
        };

        let api = self.clone();
        let get_content = move |req: &mut Request| -> IronResult<Response> {
            let ref hash = req.extensions
                .get::<Router>()
                .unwrap()
                .find("hash")
                .unwrap(); // TODO remove unwrap!
            let content = api.get_content(&hash)?;

            let content_type = Mime(TopLevel::Application, SubLevel::Json, Vec::new());
            let response = Response::with((content_type, status::Ok, json!(content).to_string()));
            Ok(response)
        };

        let api = self.clone();
        let get_proof = move |req: &mut Request| -> IronResult<Response> {
            let ref hash = req.extensions
                .get::<Router>()
                .unwrap()
                .find("hash")
                .unwrap();
            let content = api.get_proof(&hash)?;

            let content_type = Mime(TopLevel::Application, SubLevel::Json, Vec::new());
            let response = Response::with((content_type, status::Ok, json!(content).to_string()));
            Ok(response)
        };

        router.get("/v1/content/:hash", get_content, "get_content");
        router.get("/v1/proof/:hash", get_proof, "get_proof");
        router.post("/v1/content", put_content, "put_content");
    }
}
<commit_msg>Make api more safe<commit_after>mod error;

use router::Router;
use iron::prelude::*;
use params::{Params, Value};
use params;
use chrono::UTC;

use exonum::crypto::{Hash, HexValue, Signature};
use exonum::blockchain::Blockchain;
use exonum::node::TransactionSend;
use exonum::api::Api;
use exonum::storage::MapProof;

use {TimestampTx, TimestampingSchema, Content};
pub use self::error::Error as ApiError;

#[derive(Clone)]
pub struct PublicApi<T: TransactionSend + Clone> {
    channel: T,
    blockchain: Blockchain,
}

impl<T> PublicApi<T>
where
    T: TransactionSend + Clone,
{
    pub fn new(blockchain: Blockchain, channel: T) -> PublicApi<T> {
        PublicApi {
            blockchain: blockchain,
            channel: channel,
        }
    }

    fn put_content(&self, hash_str: &str, description: &str) -> Result<TimestampTx, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let snapshot = self.blockchain.snapshot();

        if TimestampingSchema::new(&snapshot)
            .contents()
            .get(&hash)
            .is_some()
        {
            return Err(ApiError::FileExists(hash));
        }
        // Create transaction
        let ts = UTC::now().timestamp();
        let tx = TimestampTx::new_with_signature(&description, ts, &hash, &Signature::zero());
        self.channel.send(Box::new(tx.clone()))?;
        Ok(tx)
    }

    fn get_content(&self, hash_str: &str) -> Result<Content, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let view = self.blockchain.snapshot();
        TimestampingSchema::new(&view)
            .contents()
            .get(&hash)
            .ok_or_else(|| ApiError::FileNotFound(hash))
    }

    fn get_proof(&self, hash_str: &str) -> Result<MapProof<Content>, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        let view = self.blockchain.snapshot();
        let schema = TimestampingSchema::new(&view);
        Ok(schema.contents().get_proof(&hash))
    }
}

fn find_str<'a>(map: &'a params::Map, path: &[&str]) -> Result<&'a str, ApiError> {
    let value = map.find(path);
    if let Some(&Value::String(ref s)) = value {
        Ok(s)
    } else {
        Err(ApiError::IncorrectRequest)
    }
}

impl<T> Api for PublicApi<T>
where
    T: TransactionSend + Clone + 'static,
{
    // FIXME Rewrite without unwrap and boiler-plate code
    fn wire(&self, router: &mut Router) {
        // Receive a message by POST and play it back.
        let api = self.clone();
        let put_content = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();

            let hash = find_str(map, &["hash"])?;
            let description = find_str(map, &["description"]).unwrap_or("");

            let tx = api.put_content(hash, description)?;
            api.ok_response(&json!(tx))
        };

        let api = self.clone();
        let get_content = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();

            let hash = find_str(map, &["hash"])?;
            let content = api.get_content(&hash)?;

            api.ok_response(&json!(content))
        };

        let api = self.clone();
        let get_proof = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();

            let hash = find_str(map, &["hash"])?;
            let proof = api.get_proof(&hash)?;

            api.ok_response(&json!(proof))
        };

        router.get("/v1/content/:hash", get_content, "get_content");
        router.get("/v1/proof/:hash", get_proof, "get_proof");
        router.post("/v1/content", put_content, "put_content");
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use glob::Paths;
use semver::Version;

use error::{StoreError, StoreErrorKind};
use store::Result;
use store::Store;

/// The Index into the Store
pub type StoreId = PathBuf;

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split("~").last().map(|v| Version::parse(v).is_err()).unwrap_or(false) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(StoreError::new(StoreErrorKind::StorePathLacksVersion, None));
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.chars().next() == Some('/') {
        path.push(&path_elem[1..path_elem.len()]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    self.0
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    paths: Paths,
}

impl StoreIdIterator {

    pub fn new(paths: Paths) -> StoreIdIterator {
        StoreIdIterator {
            paths: paths,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.paths.next().and_then(|o| o.ok())
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<commit_msg>Implement Debug for StoreIdIterator<commit_after>use std::path::PathBuf;
use glob::Paths;
use semver::Version;
use std::fmt::{Debug, Formatter};
use std::fmt::Error as FmtError;
use std::result::Result as RResult;

use error::{StoreError, StoreErrorKind};
use store::Result;
use store::Store;

/// The Index into the Store
pub type StoreId = PathBuf;

/// This Trait allows you to convert various representations to a single one
/// suitable for usage in the Store
pub trait IntoStoreId {
    fn into_storeid(self) -> StoreId;
}

impl IntoStoreId for PathBuf {
    fn into_storeid(self) -> StoreId {
        self
    }
}

pub fn build_entry_path(store: &Store, path_elem: &str) -> Result<PathBuf> {
    debug!("Checking path element for version");
    if path_elem.split("~").last().map(|v| Version::parse(v).is_err()).unwrap_or(false) {
        debug!("Version cannot be parsed from {:?}", path_elem);
        debug!("Path does not contain version!");
        return Err(StoreError::new(StoreErrorKind::StorePathLacksVersion, None));
    }
    debug!("Version checking succeeded");

    debug!("Building path from {:?}", path_elem);
    let mut path = store.path().clone();

    if path_elem.chars().next() == Some('/') {
        path.push(&path_elem[1..path_elem.len()]);
    } else {
        path.push(path_elem);
    }

    Ok(path)
}

#[macro_export]
macro_rules! module_entry_path_mod {
    ($name:expr, $version:expr) => (
        #[deny(missing_docs,
                missing_copy_implementations,
                trivial_casts, trivial_numeric_casts,
                unsafe_code,
                unstable_features,
                unused_import_braces, unused_qualifications,
                unused_imports)]
        /// A helper module to create valid module entry paths
        pub mod module_path {
            use semver::Version;
            use std::convert::AsRef;
            use std::path::Path;
            use std::path::PathBuf;

            /// A Struct giving you the ability to choose store entries assigned
            /// to it.
            ///
            /// It is created through a call to `new`.
            pub struct ModuleEntryPath(PathBuf);

            impl ModuleEntryPath {
                /// Path has to be a valid UTF-8 string or this will panic!
                pub fn new<P: AsRef<Path>>(pa: P) -> ModuleEntryPath {
                    let mut path = PathBuf::new();
                    path.push(format!("{}", $name));
                    path.push(pa.as_ref().clone());
                    let version = Version::parse($version).unwrap();
                    let name = pa.as_ref().file_name().unwrap()
                        .to_str().unwrap();
                    path.set_file_name(format!("{}~{}",
                                               name,
                                               version));
                    ModuleEntryPath(path)
                }
            }

            impl $crate::storeid::IntoStoreId for ModuleEntryPath {
                fn into_storeid(self) -> $crate::storeid::StoreId {
                    self.0
                }
            }
        }
    )
}

pub struct StoreIdIterator {
    paths: Paths,
}

impl Debug for StoreIdIterator {

    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreIdIterator")
    }

}

impl StoreIdIterator {

    pub fn new(paths: Paths) -> StoreIdIterator {
        StoreIdIterator {
            paths: paths,
        }
    }

}

impl Iterator for StoreIdIterator {
    type Item = StoreId;

    fn next(&mut self) -> Option<StoreId> {
        self.paths.next().and_then(|o| o.ok())
    }

}

#[cfg(test)]
mod test {

    use storeid::IntoStoreId;

    module_entry_path_mod!("test", "0.2.0-alpha+leet1337");

    #[test]
    fn correct_path() {
        let p = module_path::ModuleEntryPath::new("test");

        assert_eq!(p.into_storeid().to_str().unwrap(), "test/test~0.2.0-alpha+leet1337");
    }

}
<|endoftext|>