<commit_before>use std::io::{self,Error,ErrorKind};
use futures::{Async,Future,future,Stream};
use amq_protocol::types::*;
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};
use std::default::Default;
use lapin_async::api::RequestId;
use lapin_async::queue::Message;
use lapin_async::generated::basic;

use transport::*;
use consumer::Consumer;
use client::wait_for_answer;

/// `Channel` provides methods to act on a channel, such as managing queues
//#[derive(Clone)]
pub struct Channel<T> {
  pub transport: Arc<Mutex<AMQPTransport<T>>>,
  pub id:    u16,
}

impl<T> Clone for Channel<T> {
  fn clone(&self) -> Channel<T> {
    Channel {
      transport: self.transport.clone(),
      id:        self.id,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct QueueDeclareOptions {
  pub passive:     bool,
  pub durable:     bool,
  pub exclusive:   bool,
  pub auto_delete: bool,
  pub nowait:      bool,
}

impl Default for QueueDeclareOptions {
  fn default() -> QueueDeclareOptions {
    QueueDeclareOptions {
      passive:     false,
      durable:     false,
      exclusive:   false,
      auto_delete: false,
      nowait:      false,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct BasicPublishOptions {
  pub ticket:    u16,
  pub exchange:  String,
  pub mandatory: bool,
  pub immediate: bool,
}

impl Default for BasicPublishOptions {
  fn default() -> BasicPublishOptions {
    BasicPublishOptions {
      ticket:    0,
      exchange:  "".to_string(),
      mandatory: false,
      immediate: false,
    }
  }
}

pub type BasicProperties = basic::Properties;

#[derive(Clone,Debug,PartialEq)]
pub struct BasicConsumeOptions {
  pub ticket:    u16,
  pub no_local:  bool,
  pub no_ack:    bool,
  pub exclusive: bool,
  pub no_wait:   bool,
}

impl Default for BasicConsumeOptions {
  fn default() -> BasicConsumeOptions {
    BasicConsumeOptions {
      ticket:    0,
      no_local:  false,
      no_ack:    false,
      exclusive: false,
      no_wait:   false,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct BasicGetOptions {
  pub ticket:    u16,
  pub no_ack:    bool,
}

impl Default for BasicGetOptions {
  fn default() -> BasicGetOptions {
    BasicGetOptions {
      ticket:    0,
      no_ack:    false,
    }
  }
}

impl<T: AsyncRead+AsyncWrite+'static> Channel<T> {
  /// creates a queue
  ///
  /// returns a future that resolves once the queue is available
  ///
  /// the `mandatory` and `ìmmediate` options can be set to true,
  /// but the return message will not be handled
  pub fn queue_declare(&self, name: &str, options: &QueueDeclareOptions) -> 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(),
        options.passive, options.durable, options.exclusive, options.auto_delete, options.nowait, FieldTable::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not declare queue: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("queue_declare request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          trace!("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"))
      ))
    }
  }

  /// sets up confirm extension for this channel
  pub fn confirm_select(&self) -> Box<Future<Item = (), Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.confirm_select(self.id, false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not activate confirm extension: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("confirm select request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          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 activate confirm extension"))
      ))
    }
  }

  /// publishes a message on a queue
  ///
  /// the future's result is:
  /// - `Some(true)` if we're on a confirm channel and the message was ack'd
  /// - `Some(false)` if we're on a confirm channel and the message was nack'd
  /// - `None` if we're not on a confirm channel
  pub fn basic_publish(&self, queue: &str, payload: &[u8], options: &BasicPublishOptions, properties: BasicProperties) -> Box<Future<Item = Option<bool>, Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      //FIXME: does not handle the return messages with mandatory and immediate
      match transport.conn.basic_publish(self.id, options.ticket, options.exchange.clone(),
        queue.to_string(), options.mandatory, options.immediate) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(delivery_tag) => {
          transport.send_frames();
          transport.conn.send_content_frames(self.id, 60, payload, properties);
          transport.send_frames();

          transport.handle_frames();
          if transport.conn.channels.get_mut(&self.id).map(|c| c.confirm).unwrap_or(false) {
            wait_for_basic_publish_confirm(cl_transport, delivery_tag, self.id)
          } else {
            Box::new(future::ok(None))
          }
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// creates a consumer stream
  ///
  /// returns a future of a `Consumer` that resolves once the method succeeds
  ///
  /// `Consumer` implements `futures::Stream`, so it can be used with any of
  /// the usual combinators
  pub fn basic_consume(&self, queue: &str, consumer_tag: &str, options: &BasicConsumeOptions) -> Box<Future<Item = Consumer<T>, Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_consume(self.id, options.ticket, queue.to_string(), consumer_tag.to_string(),
        options.no_local, options.no_ack, options.exclusive, options.no_wait, FieldTable::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not start consumer")))
        ),
        Ok(request_id) => {
          transport.send_frames();

          transport.handle_frames();

          let consumer = Consumer {
            transport:    cl_transport.clone(),
            channel_id:   self.id,
            queue:        queue.to_string(),
            consumer_tag: consumer_tag.to_string(),
          };

          trace!("basic_consume returning closure");
          Box::new(wait_for_answer(cl_transport, request_id).map(move |_| {
            trace!("basic_consume received response, returning consumer");
            consumer
          }))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// acks a message
  pub fn basic_ack(&self, delivery_tag: u64) -> Box<Future<Item = (), Error = io::Error>> {
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_ack(self.id, delivery_tag, false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(_) => {
          transport.send_frames();
          Box::new(future::ok(()))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// rejects a message
  pub fn basic_reject(&self, delivery_tag: u64, requeue: bool) -> Box<Future<Item = (), Error = io::Error>> {
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_reject(self.id, delivery_tag, requeue) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(_) => {
          transport.send_frames();
          Box::new(future::ok(()))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// acks a message
  pub fn basic_get(&self, queue: &str, options: &BasicGetOptions) -> Box<Future<Item = Message, Error = io::Error>> {
    let cl_transport = self.transport.clone();
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_get(self.id, options.ticket, queue.to_string(), options.no_ack) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(request_id) => {
          transport.send_frames();
          transport.handle_frames();
          wait_for_basic_get_answer(cl_transport, request_id, self.id, queue)
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// purges a queue
  pub fn queue_purge(&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_purge(self.id, 0, name.to_string(), false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not purge queue: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("purge request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          trace!("purge 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 purge queue {}", name))
      ))
    }
  }
}

/// internal method to wait until a basic get succeeded
pub fn wait_for_basic_get_answer<T: AsyncRead+AsyncWrite+'static>(transport: Arc<Mutex<AMQPTransport<T>>>,
  request_id: RequestId, channel_id: u16, queue: &str) -> Box<Future<Item = Message, Error = io::Error>> {

  let receive_transport = transport.clone();
  let queue = queue.to_string();

  let request_future = future::poll_fn(move || {
    let result = if let Ok(mut tr) = transport.try_lock() {
      tr.handle_frames();
      match tr.conn.finished_get_result(request_id) {
        None =>  {
          tr.handle_frames();
          if let Some(res) = tr.conn.finished_get_result(request_id) {
            res
          } else {
            return Ok(Async::NotReady);
          }
        },
        Some(res) => res,
      }
    } else {
      return Ok(Async::NotReady);
    };

    if result {
      Ok(Async::Ready(()))
    } else {
      Err(Error::new(ErrorKind::Other, format!("basic get returned empty")))
    }
  });

  let receive_future = future::poll_fn(move || {
    if let Ok(mut transport) = receive_transport.try_lock() {
      transport.handle_frames();
      if let Some(message) = transport.conn.next_get_message(channel_id, &queue) {
        Ok(Async::Ready(message))
      } else {
        transport.upstream.poll();
        transport.heartbeat.poll();
        trace!("basic get[{}-{}] not ready", channel_id, queue);
        Ok(Async::NotReady)
      }
    } else {
      return Ok(Async::NotReady);
    }
  });

  Box::new(request_future.and_then(|_| receive_future))
}

/// internal method to wait until a basic publish confirmation comes back
pub fn wait_for_basic_publish_confirm<T: AsyncRead+AsyncWrite+'static>(transport: Arc<Mutex<AMQPTransport<T>>>,
  delivery_tag: u64, channel_id: u16) -> Box<Future<Item = Option<bool>, Error = io::Error>> {

  Box::new(future::poll_fn(move || {
    if let Ok(mut tr) = transport.try_lock() {
      tr.handle_frames();
      let acked_opt = tr.conn.channels.get_mut(&channel_id).map(|c| {
        if c.acked.remove(&delivery_tag) {
          Some(true)
        } else if c.nacked.remove(&delivery_tag) {
          Some(false)
        } else {
          info!("message with tag {} still in unacked: {:?}", delivery_tag, c.unacked);
          None
        }
      }).unwrap();

      if acked_opt.is_some() {
        return Ok(Async::Ready(acked_opt));
      } else {
        tr.upstream.poll();
        return Ok(Async::NotReady);
      }
    } else {
      return Ok(Async::NotReady);
    };

  }))
}
<commit_msg>futures: add missing handle_frames in ack and reject<commit_after>use std::io::{self,Error,ErrorKind};
use futures::{Async,Future,future,Stream};
use amq_protocol::types::*;
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};
use std::default::Default;
use lapin_async::api::RequestId;
use lapin_async::queue::Message;
use lapin_async::generated::basic;

use transport::*;
use consumer::Consumer;
use client::wait_for_answer;

/// `Channel` provides methods to act on a channel, such as managing queues
//#[derive(Clone)]
pub struct Channel<T> {
  pub transport: Arc<Mutex<AMQPTransport<T>>>,
  pub id:    u16,
}

impl<T> Clone for Channel<T> {
  fn clone(&self) -> Channel<T> {
    Channel {
      transport: self.transport.clone(),
      id:        self.id,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct QueueDeclareOptions {
  pub passive:     bool,
  pub durable:     bool,
  pub exclusive:   bool,
  pub auto_delete: bool,
  pub nowait:      bool,
}

impl Default for QueueDeclareOptions {
  fn default() -> QueueDeclareOptions {
    QueueDeclareOptions {
      passive:     false,
      durable:     false,
      exclusive:   false,
      auto_delete: false,
      nowait:      false,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct BasicPublishOptions {
  pub ticket:    u16,
  pub exchange:  String,
  pub mandatory: bool,
  pub immediate: bool,
}

impl Default for BasicPublishOptions {
  fn default() -> BasicPublishOptions {
    BasicPublishOptions {
      ticket:    0,
      exchange:  "".to_string(),
      mandatory: false,
      immediate: false,
    }
  }
}

pub type BasicProperties = basic::Properties;

#[derive(Clone,Debug,PartialEq)]
pub struct BasicConsumeOptions {
  pub ticket:    u16,
  pub no_local:  bool,
  pub no_ack:    bool,
  pub exclusive: bool,
  pub no_wait:   bool,
}

impl Default for BasicConsumeOptions {
  fn default() -> BasicConsumeOptions {
    BasicConsumeOptions {
      ticket:    0,
      no_local:  false,
      no_ack:    false,
      exclusive: false,
      no_wait:   false,
    }
  }
}

#[derive(Clone,Debug,PartialEq)]
pub struct BasicGetOptions {
  pub ticket:    u16,
  pub no_ack:    bool,
}

impl Default for BasicGetOptions {
  fn default() -> BasicGetOptions {
    BasicGetOptions {
      ticket:    0,
      no_ack:    false,
    }
  }
}

impl<T: AsyncRead+AsyncWrite+'static> Channel<T> {
  /// creates a queue
  ///
  /// returns a future that resolves once the queue is available
  ///
  /// the `mandatory` and `ìmmediate` options can be set to true,
  /// but the return message will not be handled
  pub fn queue_declare(&self, name: &str, options: &QueueDeclareOptions) -> 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(),
        options.passive, options.durable, options.exclusive, options.auto_delete, options.nowait, FieldTable::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not declare queue: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("queue_declare request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          trace!("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"))
      ))
    }
  }

  /// sets up confirm extension for this channel
  pub fn confirm_select(&self) -> Box<Future<Item = (), Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.confirm_select(self.id, false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not activate confirm extension: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("confirm select request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          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 activate confirm extension"))
      ))
    }
  }

  /// publishes a message on a queue
  ///
  /// the future's result is:
  /// - `Some(true)` if we're on a confirm channel and the message was ack'd
  /// - `Some(false)` if we're on a confirm channel and the message was nack'd
  /// - `None` if we're not on a confirm channel
  pub fn basic_publish(&self, queue: &str, payload: &[u8], options: &BasicPublishOptions, properties: BasicProperties) -> Box<Future<Item = Option<bool>, Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      //FIXME: does not handle the return messages with mandatory and immediate
      match transport.conn.basic_publish(self.id, options.ticket, options.exchange.clone(),
        queue.to_string(), options.mandatory, options.immediate) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(delivery_tag) => {
          transport.send_frames();
          transport.conn.send_content_frames(self.id, 60, payload, properties);
          transport.send_frames();

          transport.handle_frames();
          if transport.conn.channels.get_mut(&self.id).map(|c| c.confirm).unwrap_or(false) {
            wait_for_basic_publish_confirm(cl_transport, delivery_tag, self.id)
          } else {
            Box::new(future::ok(None))
          }
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// creates a consumer stream
  ///
  /// returns a future of a `Consumer` that resolves once the method succeeds
  ///
  /// `Consumer` implements `futures::Stream`, so it can be used with any of
  /// the usual combinators
  pub fn basic_consume(&self, queue: &str, consumer_tag: &str, options: &BasicConsumeOptions) -> Box<Future<Item = Consumer<T>, Error = io::Error>> {
    let cl_transport = self.transport.clone();

    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_consume(self.id, options.ticket, queue.to_string(), consumer_tag.to_string(),
        options.no_local, options.no_ack, options.exclusive, options.no_wait, FieldTable::new()) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not start consumer")))
        ),
        Ok(request_id) => {
          transport.send_frames();

          transport.handle_frames();

          let consumer = Consumer {
            transport:    cl_transport.clone(),
            channel_id:   self.id,
            queue:        queue.to_string(),
            consumer_tag: consumer_tag.to_string(),
          };

          trace!("basic_consume returning closure");
          Box::new(wait_for_answer(cl_transport, request_id).map(move |_| {
            trace!("basic_consume received response, returning consumer");
            consumer
          }))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// acks a message
  pub fn basic_ack(&self, delivery_tag: u64) -> Box<Future<Item = (), Error = io::Error>> {
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_ack(self.id, delivery_tag, false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(_) => {
          transport.send_frames();
          transport.handle_frames();
          Box::new(future::ok(()))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// rejects a message
  pub fn basic_reject(&self, delivery_tag: u64, requeue: bool) -> Box<Future<Item = (), Error = io::Error>> {
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_reject(self.id, delivery_tag, requeue) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(_) => {
          transport.send_frames();
          transport.handle_frames();
          Box::new(future::ok(()))
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// acks a message
  pub fn basic_get(&self, queue: &str, options: &BasicGetOptions) -> Box<Future<Item = Message, Error = io::Error>> {
    let cl_transport = self.transport.clone();
    if let Ok(mut transport) = self.transport.lock() {
      match transport.conn.basic_get(self.id, options.ticket, queue.to_string(), options.no_ack) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not publish: {:?}", e)))
        ),
        Ok(request_id) => {
          transport.send_frames();
          transport.handle_frames();
          wait_for_basic_get_answer(cl_transport, request_id, self.id, queue)
        },
      }
    } else {
      //FIXME: if we're there, it means the mutex failed
      Box::new(future::err(
        Error::new(ErrorKind::ConnectionAborted, format!("could not create channel"))
      ))
    }
  }

  /// purges a queue
  pub fn queue_purge(&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_purge(self.id, 0, name.to_string(), false) {
        Err(e) => Box::new(
          future::err(Error::new(ErrorKind::ConnectionAborted, format!("could not purge queue: {:?}", e)))
        ),
        Ok(request_id) => {
          trace!("purge request id: {}", request_id);
          transport.send_frames();

          transport.handle_frames();

          trace!("purge 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 purge queue {}", name))
      ))
    }
  }
}

/// internal method to wait until a basic get succeeded
pub fn wait_for_basic_get_answer<T: AsyncRead+AsyncWrite+'static>(transport: Arc<Mutex<AMQPTransport<T>>>,
  request_id: RequestId, channel_id: u16, queue: &str) -> Box<Future<Item = Message, Error = io::Error>> {

  let receive_transport = transport.clone();
  let queue = queue.to_string();

  let request_future = future::poll_fn(move || {
    let result = if let Ok(mut tr) = transport.try_lock() {
      tr.handle_frames();
      match tr.conn.finished_get_result(request_id) {
        None =>  {
          tr.handle_frames();
          if let Some(res) = tr.conn.finished_get_result(request_id) {
            res
          } else {
            return Ok(Async::NotReady);
          }
        },
        Some(res) => res,
      }
    } else {
      return Ok(Async::NotReady);
    };

    if result {
      Ok(Async::Ready(()))
    } else {
      Err(Error::new(ErrorKind::Other, format!("basic get returned empty")))
    }
  });

  let receive_future = future::poll_fn(move || {
    if let Ok(mut transport) = receive_transport.try_lock() {
      transport.handle_frames();
      if let Some(message) = transport.conn.next_get_message(channel_id, &queue) {
        Ok(Async::Ready(message))
      } else {
        transport.upstream.poll();
        transport.heartbeat.poll();
        trace!("basic get[{}-{}] not ready", channel_id, queue);
        Ok(Async::NotReady)
      }
    } else {
      return Ok(Async::NotReady);
    }
  });

  Box::new(request_future.and_then(|_| receive_future))
}

/// internal method to wait until a basic publish confirmation comes back
pub fn wait_for_basic_publish_confirm<T: AsyncRead+AsyncWrite+'static>(transport: Arc<Mutex<AMQPTransport<T>>>,
  delivery_tag: u64, channel_id: u16) -> Box<Future<Item = Option<bool>, Error = io::Error>> {

  Box::new(future::poll_fn(move || {
    if let Ok(mut tr) = transport.try_lock() {
      tr.handle_frames();
      let acked_opt = tr.conn.channels.get_mut(&channel_id).map(|c| {
        if c.acked.remove(&delivery_tag) {
          Some(true)
        } else if c.nacked.remove(&delivery_tag) {
          Some(false)
        } else {
          info!("message with tag {} still in unacked: {:?}", delivery_tag, c.unacked);
          None
        }
      }).unwrap();

      if acked_opt.is_some() {
        return Ok(Async::Ready(acked_opt));
      } else {
        tr.upstream.poll();
        return Ok(Async::NotReady);
      }
    } else {
      return Ok(Async::NotReady);
    };

  }))
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use structopt::StructOpt;

fn run_program(tape: &mut [isize]) {
    let mut ip = 0; // instruction pointer
    loop {
        match tape[ip] {
            1 => {
                let plhs = tape[ip + 1] as usize;
                let prhs = tape[ip + 2] as usize;
                let pout = tape[ip + 3] as usize;
                tape[pout] = tape[plhs] + tape[prhs];
                ip += 4;
            }
            2 => {
                let plhs = tape[ip + 1] as usize;
                let prhs = tape[ip + 2] as usize;
                let pout = tape[ip + 3] as usize;
                tape[pout] = tape[plhs] * tape[prhs];
                ip += 4;
            }
            99 => break,
            bad_op => panic!("Invalid instruction at position {}: {}", ip, bad_op),
        }
    }
}

fn part1(input: &[isize]) -> isize {
    let mut input = input.to_vec();
    input[1] = 12;
    input[2] = 2;
    run_program(&mut input);
    input[0]
}

fn main() {
    let input: Vec<_> = std::fs::read_to_string(Opt::from_args().input)
        .expect("error reading file")
        .split(',')
        .map(|num| {
            num.trim()
                .parse::<isize>()
                .unwrap_or_else(|err| panic!("could not parse token \"{}\": {:?}", num, err))
        })
        .collect();
    println!("Part 1: {}", part1(&input));
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run_program() {
        let expected = vec![
            (
                vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50],
                vec![3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50],
            ),
            (vec![1, 0, 0, 0, 99], vec![2, 0, 0, 0, 99]),
            (vec![2, 3, 0, 3, 99], vec![2, 3, 0, 6, 99]),
            (vec![2, 4, 4, 5, 99, 0], vec![2, 4, 4, 5, 99, 9801]),
            (
                vec![1, 1, 1, 4, 99, 5, 6, 0, 99],
                vec![30, 1, 1, 4, 2, 5, 6, 0, 99],
            ),
        ];
        for (input, output) in expected {
            let mut input = input.clone();
            run_program(&mut input);
            assert_eq!(input, output);
        }
    }
}
<commit_msg>2019 day 02 part 2<commit_after>use std::path::PathBuf;
use structopt::StructOpt;

fn run_program(tape: &mut [isize]) {
    let mut ip = 0; // instruction pointer
    loop {
        match tape[ip] {
            1 => {
                let plhs = tape[ip + 1] as usize;
                let prhs = tape[ip + 2] as usize;
                let pout = tape[ip + 3] as usize;
                tape[pout] = tape[plhs] + tape[prhs];
                ip += 4;
            }
            2 => {
                let plhs = tape[ip + 1] as usize;
                let prhs = tape[ip + 2] as usize;
                let pout = tape[ip + 3] as usize;
                tape[pout] = tape[plhs] * tape[prhs];
                ip += 4;
            }
            99 => break,
            bad_op => panic!("Invalid instruction at position {}: {}", ip, bad_op),
        }
    }
}

fn part1(input: &[isize]) -> isize {
    let mut input = input.to_vec();
    input[1] = 12;
    input[2] = 2;
    run_program(&mut input);
    input[0]
}

fn part2(input: &[isize]) -> isize {
    for noun in 0..99 {
        for verb in 0..=noun {
            let mut tape = input.to_vec();
            tape[1] = noun;
            tape[2] = verb;
            run_program(&mut tape);
            if tape[0] == 19_690_720 {
                return 100 * noun + verb;
            }
        }
    }
    panic!("Input not found")
}

fn main() {
    let input: Vec<_> = std::fs::read_to_string(Opt::from_args().input)
        .expect("error reading file")
        .split(',')
        .map(|num| {
            num.trim()
                .parse::<isize>()
                .unwrap_or_else(|err| panic!("could not parse token \"{}\": {:?}", num, err))
        })
        .collect();
    println!("Part 1: {}", part1(&input));
    println!("Part 2: {}", part2(&input));
}

#[derive(StructOpt)]
struct Opt {
    #[structopt(parse(from_os_str))]
    input: PathBuf,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run_program() {
        let expected = vec![
            (
                vec![1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50],
                vec![3500, 9, 10, 70, 2, 3, 11, 0, 99, 30, 40, 50],
            ),
            (vec![1, 0, 0, 0, 99], vec![2, 0, 0, 0, 99]),
            (vec![2, 3, 0, 3, 99], vec![2, 3, 0, 6, 99]),
            (vec![2, 4, 4, 5, 99, 0], vec![2, 4, 4, 5, 99, 9801]),
            (
                vec![1, 1, 1, 4, 99, 5, 6, 0, 99],
                vec![30, 1, 1, 4, 2, 5, 6, 0, 99],
            ),
        ];
        for (input, output) in expected {
            let mut input = input.clone();
            run_program(&mut input);
            assert_eq!(input, output);
        }
    }
}
<|endoftext|>


<commit_before>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};

use crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};
use crate::entity::storage::AsStorage;
use crate::entity::view::{Bind, ClosedView};
use crate::graph::edge::{Arc, ArcKey, ArcView};
use crate::graph::geometry::{Geometric, Geometry, GraphGeometry};
use crate::graph::mutation::Consistent;
use crate::graph::vertex::{Vertex, VertexKey, VertexView};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// Non-intersecting path.
///
/// A path is an ordered set of vertices that are joined by arcs. Paths are
/// notated as either sequences or sets. An open path over vertices $A$, $B$,
/// and $C$ is notated $\overrightarrow{(A,B,C)}$ and a closed path over the
/// same vertices is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `Path` represents non-intersecting paths of the form
/// $\overrightarrow{(A,\cdots,B)}$, where $A$ is the _back_ of the path and $B$
/// is the _front_ of the path. Note that closed paths are always of the form
/// $\overrightarrow{(A,\cdots,A)}$, where the back and front vertices are both
/// $A$ (the same).
#[derive(Clone)]
pub struct Path<B>
where
    B: Reborrow,
    B::Target:
        AsStorage<Arc<Geometry<B>>> + AsStorage<Vertex<Geometry<B>>> + Consistent + Geometric,
{
    keys: VecDeque<ArcKey>,
    storage: B,
}

impl<B, M, G> Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support view APIs.
    // This bespoke `bind` function ensures that the path is not empty and that
    // the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: B, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        ArcView::bind(storage.reborrow(), ab).ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = Path {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    pub fn to_ref(&self) -> Path<&M> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{(A,\cdots)}$ is the vertex $A$.
    /// This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{XA}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{XA}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the back of the path.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{(\cdots,B)}$ is the vertex $B$.
    /// This is the destination vertex of the last arc that forms the path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{BX}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{BX}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the front of the path.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M> {
        let (key, _) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M> {
        let (_, key) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices<'a>(&'a self) -> impl Iterator<Item = VertexView<&'a M>>
    where
        M: 'a,
    {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs<'a>(&'a self) -> impl ExactSizeIterator<Item = ArcView<&'a M>>
    where
        M: 'a,
    {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| Bind::bind(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    fn bind_unchecked<I>(storage: B, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        Path { storage, keys }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }
}

impl<B, M, G> Path<B>
where
    B: ReborrowMut<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    pub fn to_mut(&mut self) -> Path<&mut M> {
        let storage = self.storage.reborrow_mut();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }
}

impl<'a, B, M, G> Path<B>
where
    B: ReborrowInto<'a, Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> Path<&'a M> {
        let Path { keys, storage, .. } = self;
        Path {
            keys,
            storage: storage.reborrow_into(),
        }
    }
}

impl<B, M, G> PartialEq for Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::buffer::FromRawBuffers;
    use crate::graph::{ClosedView, MeshGraph, Selector};
    use crate::primitive::Trigon;
    use crate::IteratorExt;

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }
}
<commit_msg>Support splitting paths at a vertex.<commit_after>use fool::BoolExt;
use std::borrow::Borrow;
use std::collections::{HashSet, VecDeque};

use crate::entity::borrow::{Reborrow, ReborrowInto, ReborrowMut};
use crate::entity::storage::AsStorage;
use crate::entity::view::{Bind, ClosedView};
use crate::graph::edge::{Arc, ArcKey, ArcView};
use crate::graph::geometry::{Geometric, Geometry, GraphGeometry};
use crate::graph::mutation::Consistent;
use crate::graph::vertex::{Vertex, VertexKey, VertexView};
use crate::graph::{GraphError, OptionExt as _, Selector};
use crate::IteratorExt as _;

/// Non-intersecting path.
///
/// A path is an ordered set of vertices that are joined by arcs. Paths are
/// notated as either sequences or sets. An open path over vertices $A$, $B$,
/// and $C$ is notated $\overrightarrow{(A,B,C)}$ and a closed path over the
/// same vertices is notated $\overrightarrow{\\{A,B,C\\}}$.
///
/// `Path` represents non-intersecting paths of the form
/// $\overrightarrow{(A,\cdots,B)}$, where $A$ is the _back_ of the path and $B$
/// is the _front_ of the path. Note that closed paths are always of the form
/// $\overrightarrow{(A,\cdots,A)}$, where the back and front vertices are both
/// $A$ (the same).
#[derive(Clone)]
pub struct Path<B>
where
    B: Reborrow,
    B::Target:
        AsStorage<Arc<Geometry<B>>> + AsStorage<Vertex<Geometry<B>>> + Consistent + Geometric,
{
    keys: VecDeque<ArcKey>,
    storage: B,
}

impl<B, M, G> Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    // Paths bind multiple keys to storage and so do not support view APIs.
    // This bespoke `bind` function ensures that the path is not empty and that
    // the topology forms a non-intersecting path.
    pub(in crate::graph) fn bind<I>(storage: B, keys: I) -> Result<Self, GraphError>
    where
        I: IntoIterator,
        I::Item: Borrow<VertexKey>,
    {
        let mut keys = keys.into_iter().map(|key| *key.borrow());
        let a = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let b = keys.next().ok_or_else(|| GraphError::TopologyMalformed)?;
        let ab = (a, b).into();
        ArcView::bind(storage.reborrow(), ab).ok_or_else(|| GraphError::TopologyNotFound)?;
        let mut path = Path {
            keys: (&[ab]).iter().cloned().collect(),
            storage,
        };
        for key in keys {
            path.push_front(Selector::ByKey(key))?;
        }
        Ok(path)
    }

    pub fn to_ref(&self) -> Path<&M> {
        let storage = self.storage.reborrow();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }

    /// Pushes a vertex onto the back of the path.
    ///
    /// The back of a path $\overrightarrow{(A,\cdots)}$ is the vertex $A$.
    /// This is the source vertex of the first arc that forms the path.
    ///
    /// The given vertex must be a source vertex of an arc formed with the the
    /// back of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{XA}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{XA}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the back of the path.
    pub fn push_back(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let back = self.back();
        let xa = match destination {
            Selector::ByKey(key) => back
                .incoming_arcs()
                .find(|arc| arc.into_source_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = back
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (x, back.key()).into()
            }
        };
        let (x, _) = xa.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the front of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_back(xa);
            Ok(xa)
        }
    }

    /// Pops a vertex from the back of the path.
    pub fn pop_back(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_back()
        }
        else {
            None
        }
    }

    /// Pushes a vertex onto the front of the path.
    ///
    /// The front of a path $\overrightarrow{(\cdots,B)}$ is the vertex $B$.
    /// This is the destination vertex of the last arc that forms the path.
    ///
    /// The given vertex must be a destination vertex of an arc formed with the
    /// the front of the path. That is, if the given vertex is $X$, then
    /// $\overrightarrow{BX}$ must exist.
    ///
    /// Returns the key of the arc $\overrightarrow{BX}$ inserted into the path
    /// using the given source vertex $X$.
    ///
    /// # Errors
    ///
    /// Returns an error if the path is closed, the given vertex is not found,
    /// or the given vertex does not form an arc with the front of the path.
    pub fn push_front(&mut self, destination: Selector<VertexKey>) -> Result<ArcKey, GraphError> {
        self.is_open()
            .ok_or_else(|| GraphError::TopologyMalformed)?;
        let front = self.front();
        let bx = match destination {
            Selector::ByKey(key) => front
                .outgoing_arcs()
                .find(|arc| arc.into_destination_vertex().key() == key)
                .ok_or_else(|| GraphError::TopologyMalformed)?
                .key(),
            Selector::ByIndex(index) => {
                let x = front
                    .adjacent_vertices()
                    .keys()
                    .nth(index)
                    .ok_or_else(|| GraphError::TopologyNotFound)?;
                (front.key(), x).into()
            }
        };
        let (_, x) = bx.into();
        // Do not allow intersections unless they form a loop with the first
        // vertex in the path (this iteration skips the vertex at the back of
        // the path).
        let is_intersecting = self
            .arcs()
            .map(|arc| arc.into_destination_vertex())
            .keys()
            .any(|key| key == x);
        if is_intersecting {
            Err(GraphError::TopologyMalformed)
        }
        else {
            self.keys.push_front(bx);
            Ok(bx)
        }
    }

    /// Pops a vertex from the front of the path.
    pub fn pop_front(&mut self) -> Option<ArcKey> {
        // Empty paths are forbidden.
        if self.keys.len() > 1 {
            self.keys.pop_front()
        }
        else {
            None
        }
    }

    /// Gets the vertex at the back of the path.
    pub fn back(&self) -> VertexView<&M> {
        let (key, _) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets the vertex at the front of the path.
    pub fn front(&self) -> VertexView<&M> {
        let (_, key) = self.endpoints();
        Bind::bind(self.storage.reborrow(), key).expect_consistent()
    }

    /// Gets an iterator over the vertices in the path.
    pub fn vertices<'a>(&'a self) -> impl Iterator<Item = VertexView<&'a M>>
    where
        M: 'a,
    {
        let back = self.back();
        Some(back)
            .into_iter()
            .chain(self.arcs().map(|arc| arc.into_destination_vertex()))
    }

    /// Gets an iterator over the arcs in the path.
    pub fn arcs<'a>(&'a self) -> impl ExactSizeIterator<Item = ArcView<&'a M>>
    where
        M: 'a,
    {
        let storage = self.storage.reborrow();
        self.keys
            .iter()
            .rev()
            .cloned()
            .map(move |key| Bind::bind(storage, key).expect_consistent())
    }

    /// Returns `true` if the path is open.
    ///
    /// An _open path_ is a path that terminates and does **not** form a loop.
    pub fn is_open(&self) -> bool {
        !self.is_closed()
    }

    /// Returns `true` if the path is closed.
    ///
    /// A _closed path_ is a path that forms a loop by starting and ending at
    /// the same vertex.
    pub fn is_closed(&self) -> bool {
        let (a, b) = self.endpoints();
        a == b
    }

    fn bind_unchecked<I>(storage: B, keys: I) -> Self
    where
        I: IntoIterator,
        I::Item: Borrow<ArcKey>,
    {
        let keys = keys.into_iter().map(|key| *key.borrow()).collect();
        Path { storage, keys }
    }

    fn endpoints(&self) -> (VertexKey, VertexKey) {
        let (a, _) = self.keys.back().cloned().expect("empty path").into();
        let (_, b) = self.keys.front().cloned().expect("empty pathy").into();
        (a, b)
    }
}

impl<B, M, G> Path<B>
where
    B: ReborrowMut<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    pub fn to_mut(&mut self) -> Path<&mut M> {
        let storage = self.storage.reborrow_mut();
        let keys = self.keys.iter();
        Path::bind_unchecked(storage, keys)
    }
}

impl<'a, B, M, G> Path<B>
where
    B: ReborrowInto<'a, Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    /// Converts a mutable view into an immutable view.
    ///
    /// This is useful when mutations are not (or no longer) needed and mutual
    /// access is desired.
    pub fn into_ref(self) -> Path<&'a M> {
        let Path { keys, storage, .. } = self;
        Path {
            keys,
            storage: storage.reborrow_into(),
        }
    }

    /// Splits the path into two immutable paths at the given vertex.
    ///
    /// Given a path $\overrightarrow{(A,\cdots,M,\cdots,B)}$, splitting at the
    /// vertex $M$ results in the paths $\overrightarrow{(A,\cdots,M)}$ and
    /// $\overrightarrow{(M,\cdots,B)}$.
    ///
    /// **Splitting a path does not mutate its graph in any way** (unlike
    /// `ArcView::split` or `FaceView::split`, for example). To split a graph
    /// along a path (and thus mutate the graph) use `MeshGraph::split_at_path`.
    ///
    /// It is not possible to split a path at its back or front vertices.
    ///
    /// # Errors
    ///
    /// Returns an error if the given vertex cannot be found or the path cannot
    /// be split at that vertex.
    pub fn split(self, at: Selector<VertexKey>) -> Result<(Path<&'a M>, Path<&'a M>), GraphError> {
        let index = at.index_or_else(|key| {
            self.vertices()
                .keys()
                .enumerate()
                .find(|(_, a)| *a == key)
                .map(|(n, _)| n)
                .ok_or_else(|| GraphError::TopologyNotFound)
        })?;
        if index == 0 || index >= self.keys.len() {
            return Err(GraphError::TopologyMalformed);
        }
        let Path {
            keys: mut right,
            storage,
            ..
        } = self.into_ref();
        let left = right.split_off(index);
        Ok((
            Path::bind_unchecked(storage, left),
            Path::bind_unchecked(storage, right),
        ))
    }
}

impl<B, M, G> PartialEq for Path<B>
where
    B: Reborrow<Target = M>,
    M: AsStorage<Arc<G>> + AsStorage<Vertex<G>> + Consistent + Geometric<Geometry = G>,
    G: GraphGeometry,
{
    fn eq(&self, other: &Self) -> bool {
        let keys = |path: &Self| path.arcs().keys().collect::<HashSet<_>>();
        keys(self) == keys(other)
    }
}

#[cfg(test)]
mod tests {
    use nalgebra::Point2;

    use crate::graph::{ClosedView, MeshGraph, Selector};
    use crate::prelude::*;
    use crate::primitive::{Tetragon, Trigon};
    use crate::IteratorExt;

    use Selector::ByKey;

    type E2 = Point2<f64>;

    #[test]
    fn open_close() {
        let graph = MeshGraph::<E2>::from_raw_buffers(
            vec![Trigon::from([0usize, 1, 2])],
            vec![(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)],
        )
        .unwrap();
        let keys = graph
            .faces()
            .nth(0)
            .unwrap()
            .interior_arcs()
            .map(|arc| arc.into_source_vertex())
            .keys()
            .collect::<Vec<_>>();

        let mut path = graph.path(keys.iter()).unwrap();
        assert!(path.is_open());
        // TODO: Move this assertion to a distinct test.
        assert_eq!(path.vertices().keys().collect::<Vec<_>>(), keys.to_vec());

        path.push_front(ByKey(keys[0])).unwrap();
        assert!(path.is_closed());
        assert_eq!(path.front().key(), path.back().key());
    }

    #[test]
    fn split() {
        let graph =
            MeshGraph::<()>::from_raw_buffers(vec![Tetragon::from([0usize, 1, 2, 3])], vec![(); 4])
                .unwrap();
        let source = graph.vertices().nth(0).unwrap();
        let destination = source
            .into_outgoing_arc()
            .into_next_arc()
            .into_destination_vertex();

        let path = source.shortest_path(destination.key()).unwrap();
        assert_eq!(path.arcs().count(), 2);

        let (left, right) = path.split(ByIndex(1)).unwrap();
        assert_eq!(left.front().key(), right.back().key());
        assert_eq!(left.arcs().count(), 1);
        assert_eq!(right.arcs().count(), 1);
    }
}
<|endoftext|>


<commit_before>use console::{Console, ConsoleTextKind};
use crossbeam_channel::{Receiver, Sender};
use ctrlc;
use getch::Getch;
use memmap::Mmap;
use pipeline::{Pipeline, PipelineInfo};
use pipeline_matcher::PathMatch;
use std::fs::{self, File};
use std::io::{Error, Write};
use std::ops::Deref;
use std::time::{Duration, Instant};
use tempfile::NamedTempFile;
use util::{catch, decode_error, exit};

// ---------------------------------------------------------------------------------------------------------------------
// PipelineReplacer
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineReplacer {
    pub is_color: bool,
    pub is_interactive: bool,
    pub print_file: bool,
    pub print_column: bool,
    pub print_row: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    console: Console,
    all_replace: bool,
    replacement: Vec<u8>,
    time_beg: Instant,
    time_bsy: Duration,
}

impl PipelineReplacer {
    pub fn new(replacement: &[u8]) -> Self {
        PipelineReplacer {
            is_color: true,
            is_interactive: true,
            print_file: true,
            print_column: false,
            print_row: false,
            infos: Vec::new(),
            errors: Vec::new(),
            console: Console::new(),
            all_replace: false,
            replacement: Vec::from(replacement),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
        }
    }

    fn replace_match(&mut self, pm: PathMatch) {
        if pm.matches.is_empty() {
            return;
        }
        self.console.is_color = self.is_color;

        let result = catch::<_, (), Error>(|| {
            let mut tmpfile = try!(NamedTempFile::new_in(pm.path.parent().unwrap_or(&pm.path)));

            let tmpfile_path = tmpfile.path().to_path_buf();
            let _ = ctrlc::set_handler(move || {
                let path = tmpfile_path.clone();
                let mut console = Console::new();
                console.write(
                    ConsoleTextKind::Info,
                    &format!("\nCleanup temporary file: {:?}\n", path),
                );
                let _ = fs::remove_file(path);
                exit(0, &mut console);
            });

            {
                let file = try!(File::open(&pm.path));
                let mmap = try!(unsafe { Mmap::map(&file) });
                let src = mmap.deref();

                let mut i = 0;
                let mut pos = 0;
                let mut column = 0;
                let mut last_lf = 0;
                for m in &pm.matches {
                    try!(tmpfile.write_all(&src[i..m.beg]));

                    let mut do_replace = true;
                    if self.is_interactive & !self.all_replace {
                        if self.print_file {
                            self.console.write(ConsoleTextKind::Filename, pm.path.to_str().unwrap());
                            self.console.write(ConsoleTextKind::Other, ": ");
                        }
                        if self.print_column | self.print_row {
                            while pos < m.beg {
                                if src[pos] == 0x0a {
                                    column += 1;
                                    last_lf = pos;
                                }
                                pos += 1;
                            }
                            if self.print_column {
                                self.console.write(ConsoleTextKind::Other, &format!("{}:", column + 1));
                            }
                            if self.print_row {
                                self.console
                                    .write(ConsoleTextKind::Other, &format!("{}:", m.beg - last_lf));
                            }
                        }

                        self.console.write_match_line(src, m);
                        self.console
                            .write(ConsoleTextKind::Other, "Replace keyword? [Y]es/[n]o/[a]ll/[q]uit:");
                        self.console.flush();
                        let getch = Getch::new();
                        let key = getch.getch()?;
                        let key = char::from(key);
                        self.console.write(ConsoleTextKind::Other, &format!("{}\n", key));
                        match key {
                            'N' | 'n' => do_replace = false,
                            'A' | 'a' => self.all_replace = true,
                            'Q' | 'q' => {
                                let _ = tmpfile.close();
                                exit(0, &mut self.console);
                            }
                            _ => do_replace = true,
                        }
                    }

                    if do_replace {
                        try!(tmpfile.write_all(&self.replacement));
                    } else {
                        try!(tmpfile.write_all(&src[m.beg..m.end]));
                    }
                    i = m.end;
                }

                if i < src.len() {
                    try!(tmpfile.write_all(&src[i..src.len()]));
                }
                try!(tmpfile.flush());
            }

            let real_path = try!(fs::canonicalize(&pm.path));

            let metadata = try!(fs::metadata(&real_path));

            try!(fs::set_permissions(tmpfile.path(), metadata.permissions()));
            try!(tmpfile.persist(&real_path));

            Ok(())
        });
        match result {
            Ok(_) => (),
            Err(e) => self.console.write(
                ConsoleTextKind::Error,
                &format!("Error: {} @ {:?}\n", decode_error(e.kind()), pm.path),
            ),
        }
    }
}

impl Pipeline<PathMatch, ()> for PipelineReplacer {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathMatch>>, tx: Sender<PipelineInfo<()>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(x, pm)) => {
                    watch_time!(self.time_bsy, {
                        self.replace_match(pm);
                        let _ = tx.send(PipelineInfo::SeqDat(x, ()));
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.time_beg = Instant::now();
                        let _ = tx.send(PipelineInfo::SeqBeg(x));
                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(x)) => {
                    for i in &self.infos {
                        let _ = tx.send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx.send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx.send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));
                    let _ = tx.send(PipelineInfo::SeqEnd(x));
                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx.send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx.send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx.send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------
<commit_msg>Default replacer to loop<commit_after>use console::{Console, ConsoleTextKind};
use crossbeam_channel::{Receiver, Sender};
use ctrlc;
use getch::Getch;
use memmap::Mmap;
use pipeline::{Pipeline, PipelineInfo};
use pipeline_matcher::PathMatch;
use std::fs::{self, File};
use std::io::{Error, Write};
use std::ops::Deref;
use std::time::{Duration, Instant};
use tempfile::NamedTempFile;
use util::{catch, decode_error, exit};

// ---------------------------------------------------------------------------------------------------------------------
// PipelineReplacer
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineReplacer {
    pub is_color: bool,
    pub is_interactive: bool,
    pub print_file: bool,
    pub print_column: bool,
    pub print_row: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    console: Console,
    all_replace: bool,
    replacement: Vec<u8>,
    time_beg: Instant,
    time_bsy: Duration,
}

impl PipelineReplacer {
    pub fn new(replacement: &[u8]) -> Self {
        PipelineReplacer {
            is_color: true,
            is_interactive: true,
            print_file: true,
            print_column: false,
            print_row: false,
            infos: Vec::new(),
            errors: Vec::new(),
            console: Console::new(),
            all_replace: false,
            replacement: Vec::from(replacement),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
        }
    }

    fn replace_match(&mut self, pm: PathMatch) {
        if pm.matches.is_empty() {
            return;
        }
        self.console.is_color = self.is_color;

        let result = catch::<_, (), Error>(|| {
            let mut tmpfile = try!(NamedTempFile::new_in(pm.path.parent().unwrap_or(&pm.path)));

            let tmpfile_path = tmpfile.path().to_path_buf();
            let _ = ctrlc::set_handler(move || {
                let path = tmpfile_path.clone();
                let mut console = Console::new();
                console.write(
                    ConsoleTextKind::Info,
                    &format!("\nCleanup temporary file: {:?}\n", path),
                );
                let _ = fs::remove_file(path);
                exit(0, &mut console);
            });

            {
                let file = try!(File::open(&pm.path));
                let mmap = try!(unsafe { Mmap::map(&file) });
                let src = mmap.deref();

                let mut i = 0;
                let mut pos = 0;
                let mut column = 0;
                let mut last_lf = 0;
                for m in &pm.matches {
                    try!(tmpfile.write_all(&src[i..m.beg]));

                    let mut do_replace = true;
                    if self.is_interactive & !self.all_replace {
                        if self.print_file {
                            self.console.write(ConsoleTextKind::Filename, pm.path.to_str().unwrap());
                            self.console.write(ConsoleTextKind::Other, ": ");
                        }
                        if self.print_column | self.print_row {
                            while pos < m.beg {
                                if src[pos] == 0x0a {
                                    column += 1;
                                    last_lf = pos;
                                }
                                pos += 1;
                            }
                            if self.print_column {
                                self.console.write(ConsoleTextKind::Other, &format!("{}:", column + 1));
                            }
                            if self.print_row {
                                self.console
                                    .write(ConsoleTextKind::Other, &format!("{}:", m.beg - last_lf));
                            }
                        }

                        self.console.write_match_line(src, m);

                        let getch = Getch::new();
                        loop {
                            self.console
                                .write(ConsoleTextKind::Other, "Replace keyword? [Y]es/[n]o/[a]ll/[q]uit: ");
                            self.console.flush();
                            let key = char::from(getch.getch()?);
                            if key != '\n' {
                                self.console.write(ConsoleTextKind::Other, &format!("{}\n", key));
                            } else {
                                self.console.write(ConsoleTextKind::Other, "\n");
                            }
                            match key {
                                'Y' | 'y' | ' ' | '\n' => do_replace = true,
                                'N' | 'n' => do_replace = false,
                                'A' | 'a' => self.all_replace = true,
                                'Q' | 'q' => {
                                    let _ = tmpfile.close();
                                    exit(0, &mut self.console);
                                }
                                _ => continue,
                            }
                            break;
                        }
                    }

                    if do_replace {
                        try!(tmpfile.write_all(&self.replacement));
                    } else {
                        try!(tmpfile.write_all(&src[m.beg..m.end]));
                    }
                    i = m.end;
                }

                if i < src.len() {
                    try!(tmpfile.write_all(&src[i..src.len()]));
                }
                try!(tmpfile.flush());
            }

            let real_path = try!(fs::canonicalize(&pm.path));

            let metadata = try!(fs::metadata(&real_path));

            try!(fs::set_permissions(tmpfile.path(), metadata.permissions()));
            try!(tmpfile.persist(&real_path));

            Ok(())
        });
        match result {
            Ok(_) => (),
            Err(e) => self.console.write(
                ConsoleTextKind::Error,
                &format!("Error: {} @ {:?}\n", decode_error(e.kind()), pm.path),
            ),
        }
    }
}

impl Pipeline<PathMatch, ()> for PipelineReplacer {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathMatch>>, tx: Sender<PipelineInfo<()>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(x, pm)) => {
                    watch_time!(self.time_bsy, {
                        self.replace_match(pm);
                        let _ = tx.send(PipelineInfo::SeqDat(x, ()));
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.time_beg = Instant::now();
                        let _ = tx.send(PipelineInfo::SeqBeg(x));
                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(x)) => {
                    for i in &self.infos {
                        let _ = tx.send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx.send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx.send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));
                    let _ = tx.send(PipelineInfo::SeqEnd(x));
                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx.send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx.send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx.send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------
<|endoftext|>


<commit_before>use spec::{LinkerFlavor, LldFlavor, PanicStrategy,
           Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
        llvm_target: "riscv32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: "unknown".to_string(),
        arch: "riscv32".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),

        options: TargetOptions {
            linker: Some("rust-lld".to_string()),
            cpu: "generic-rv32".to_string(),
            max_atomic_width: Some(32),
            atomic_cas: false, // incomplete +a extension
            features: "+m,+a,+c".to_string(),
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: "static".to_string(),
            emit_debug_gdb_scripts: false,
            abi_blacklist: super::riscv_base::abi_blacklist(),
            .. Default::default()
        },
    })
}
<commit_msg>Auto merge of #57925 - fintelia:riscv-cas, r=nagisa<commit_after>use spec::{LinkerFlavor, LldFlavor, PanicStrategy,
           Target, TargetOptions, TargetResult};

pub fn target() -> TargetResult {
    Ok(Target {
        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
        llvm_target: "riscv32".to_string(),
        target_endian: "little".to_string(),
        target_pointer_width: "32".to_string(),
        target_c_int_width: "32".to_string(),
        target_os: "none".to_string(),
        target_env: String::new(),
        target_vendor: "unknown".to_string(),
        arch: "riscv32".to_string(),
        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),

        options: TargetOptions {
            linker: Some("rust-lld".to_string()),
            cpu: "generic-rv32".to_string(),
            max_atomic_width: Some(32),
            atomic_cas: true,
            features: "+m,+a,+c".to_string(),
            executables: true,
            panic_strategy: PanicStrategy::Abort,
            relocation_model: "static".to_string(),
            emit_debug_gdb_scripts: false,
            abi_blacklist: super::riscv_base::abi_blacklist(),
            .. Default::default()
        },
    })
}
<|endoftext|>


<commit_before>use callback::AppId;
use core::intrinsics::{volatile_load, volatile_store};
use core::marker::PhantomData;
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
use core::raw::Repr;
use process::{self, Error};

pub struct Container<T: Default> {
    container_num: usize,
    ptr: PhantomData<T>
}

pub static mut CONTAINER_COUNTER : usize = 0;

pub struct Allocator<'a> {
    app: &'a mut process::Process<'a>,
    app_id: usize
}

pub struct Owned<T: ?Sized> {
    data: Unique<T>,
    app_id: usize
}

impl<T: ?Sized> Owned<T> {
    pub unsafe fn new(data: *mut T, app_id: usize) -> Owned<T> {
        Owned { data: Unique::new(data), app_id: app_id }
    }
}

impl<T: ?Sized> Drop for Owned<T> {
    fn drop(&mut self) {
        unsafe {
            let app_id = self.app_id;
            let data = self.data.get_mut() as *mut T as *mut u8;
            match process::PROCS[app_id] {
                None => {},
                Some(ref mut app) => {
                    app.free(data);
                }
            }
        }
    }
}

impl<T: ?Sized> Deref for Owned<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { self.data.get() }
    }
}

impl<T: ?Sized> DerefMut for Owned<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { self.data.get_mut() }
    }
}

impl<'a> Allocator<'a> {
    pub fn alloc<T>(&mut self, data: T) -> Result<Owned<T>, Error> {
        unsafe {
            let app_id = self.app_id;
            self.app.alloc(size_of::<T>()).map_or(Err(Error::OutOfMemory),
                |arr| {
                    let mut owned = Owned::new(arr.repr().data as *mut T, app_id);
                    *owned = data;
                    Ok(owned)
            })
        }
    }
}

impl<T: Default> Container<T> {
    pub unsafe fn create() -> Container<T> {
        let ctr = volatile_load(&CONTAINER_COUNTER);
        volatile_store(&mut CONTAINER_COUNTER, ctr + 1);
        Container {
            container_num: ctr,
            ptr: PhantomData
        }
    }

    pub fn enter<F, R>(&self, appid: AppId, fun: F) -> Result<R, Error>
        where F: FnOnce(&mut Owned<T>, &mut Allocator) -> R, R: Copy {
        unsafe {
            let app_id = appid.idx();
            match process::PROCS[app_id] {
                Some(ref mut app) => {
                    app.container_for_or_alloc::<T>(self.container_num).map_or(
                        Err(Error::OutOfMemory), move |root_ptr| {
                            let mut root = Owned::new(root_ptr, app_id);
                            let mut allocator = Allocator {
                                app: app,
                                app_id: app_id
                            };
                            let res = fun(&mut root, &mut allocator);
                            Ok(res)
                    })
                },
                None => Err(Error::NoSuchApp)
            }
        }
    }

    pub fn each<F>(&self, fun: F) where F: Fn(&mut Owned<T>) {
        unsafe {
            let itr = process::PROCS.iter_mut().filter_map(|p| p.as_mut());
            for (app_id, app) in itr.enumerate() {
                let ctr_ptr = app.container_for::<T>(self.container_num);
                if !ctr_ptr.is_null() {
                    let root_ptr = *ctr_ptr;
                    let mut root = Owned::new(root_ptr, app_id);
                    fun(&mut root);
                }
            }
        }
    }
}

<commit_msg>Applied container with pre-applied appid<commit_after>use callback::AppId;
use core::intrinsics::{volatile_load, volatile_store};
use core::marker::PhantomData;
use core::mem::size_of;
use core::ops::{Deref, DerefMut};
use core::ptr::Unique;
use core::raw::Repr;
use process::{self, Error};

pub static mut CONTAINER_COUNTER : usize = 0;

pub struct Container<T: Default> {
    container_num: usize,
    ptr: PhantomData<T>
}

pub struct AppliedContainer<T> {
    appid: usize,
    container: *mut T,
    _phantom: PhantomData<T>
}

impl<T> AppliedContainer<T> {
    pub fn enter<F,R>(self, fun: F) -> R
        where F: FnOnce(&mut Owned<T>, &mut Allocator) -> R, R: Copy {
        let mut allocator = Allocator {
            app: unsafe { process::PROCS[self.appid].as_mut().unwrap() },
            app_id: self.appid
        };
        let mut root = unsafe { Owned::new(self.container, self.appid) };
        fun(&mut root, &mut allocator)
    }
}

pub struct Allocator<'a> {
    app: &'a mut process::Process<'a>,
    app_id: usize
}

pub struct Owned<T: ?Sized> {
    data: Unique<T>,
    app_id: usize
}

impl<T: ?Sized> Owned<T> {
    pub unsafe fn new(data: *mut T, app_id: usize) -> Owned<T> {
        Owned { data: Unique::new(data), app_id: app_id }
    }

    pub fn appid(&self) -> AppId {
        unsafe {
            AppId::new(self.app_id)
        }
    }
}

impl<T: ?Sized> Drop for Owned<T> {
    fn drop(&mut self) {
        unsafe {
            let app_id = self.app_id;
            let data = self.data.get_mut() as *mut T as *mut u8;
            match process::PROCS[app_id] {
                None => {},
                Some(ref mut app) => {
                    app.free(data);
                }
            }
        }
    }
}

impl<T: ?Sized> Deref for Owned<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { self.data.get() }
    }
}

impl<T: ?Sized> DerefMut for Owned<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { self.data.get_mut() }
    }
}

impl<'a> Allocator<'a> {
    pub fn alloc<T>(&mut self, data: T) -> Result<Owned<T>, Error> {
        unsafe {
            let app_id = self.app_id;
            self.app.alloc(size_of::<T>()).map_or(Err(Error::OutOfMemory),
                |arr| {
                    let mut owned = Owned::new(arr.repr().data as *mut T, app_id);
                    *owned = data;
                    Ok(owned)
            })
        }
    }
}

impl<T: Default> Container<T> {
    pub unsafe fn create() -> Container<T> {
        let ctr = volatile_load(&CONTAINER_COUNTER);
        volatile_store(&mut CONTAINER_COUNTER, ctr + 1);
        Container {
            container_num: ctr,
            ptr: PhantomData
        }
    }

    pub fn container(&self, appid: AppId) -> Option<AppliedContainer<T>> {
        unsafe {
            let app_id = appid.idx();
            match process::PROCS[app_id] {
                Some(ref mut app) => {
                    let cntr = app.container_for::<T>(self.container_num);
                    if cntr.is_null() {
                        None
                    } else {
                        Some(AppliedContainer {
                            appid: app_id,
                            container: *cntr,
                            _phantom: PhantomData
                        })
                    }
                },
                None => None
            }
        }
    }

    pub fn enter<F, R>(&self, appid: AppId, fun: F) -> Result<R, Error>
        where F: FnOnce(&mut Owned<T>, &mut Allocator) -> R, R: Copy {
        unsafe {
            let app_id = appid.idx();
            match process::PROCS[app_id] {
                Some(ref mut app) => {
                    app.container_for_or_alloc::<T>(self.container_num).map_or(
                        Err(Error::OutOfMemory), move |root_ptr| {
                            let mut root = Owned::new(root_ptr, app_id);
                            let mut allocator = Allocator {
                                app: app,
                                app_id: app_id
                            };
                            let res = fun(&mut root, &mut allocator);
                            Ok(res)
                    })
                },
                None => Err(Error::NoSuchApp)
            }
        }
    }

    pub fn each<F>(&self, fun: F) where F: Fn(&mut Owned<T>) {
        unsafe {
            let itr = process::PROCS.iter_mut().filter_map(|p| p.as_mut());
            for (app_id, app) in itr.enumerate() {
                let ctr_ptr = app.container_for::<T>(self.container_num);
                if !ctr_ptr.is_null() {
                    let root_ptr = *ctr_ptr;
                    let mut root = Owned::new(root_ptr, app_id);
                    fun(&mut root);
                }
            }
        }
    }

    pub fn iter(&self) -> Iter<T> {
        unsafe {
            Iter {
                container: self,
                index: 0,
                len: process::PROCS.len()
            }
        }
    }
}

pub struct Iter<'a, T: 'a + Default> {
    container: &'a Container<T>,
    index: usize,
    len: usize
}

impl<'a, T: Default> Iterator for Iter<'a, T> {
    type Item = AppliedContainer<T>;

    fn next(&mut self) -> Option<Self::Item> {
        while self.index < self.len {
            let idx = self.index;
            self.index += 1;
            let res = self.container.container(unsafe { AppId::new(idx) });
            if res.is_some() {
                return res;
            }
        }
        None
    }
}

<|endoftext|>


<commit_before>use decoders::Image;
use imageops::fcol;
use imageops::OpBuffer;
use std::cmp;

pub fn demosaic_and_scale(img: &Image, minwidth: usize, minheight: usize) -> OpBuffer {
  let scale = cmp::min(img.width / minwidth, img.height / minheight);

  if scale <= 1 {
    full(img)
  } else {
    scaled(img, cmp::min(scale, 16)) // Never go less than 1/16th demosaic
  }
}

pub fn full(img: &Image) -> OpBuffer {
  let mut out = OpBuffer::new(img.width, img.height, 4);

  // First we set the colors we already have
  let mut ipos = 0;
  let mut opos = 0;
  for row in 0..img.height {
    for col in 0..img.width {
      let color = fcol(img, row, col);
      out.data[opos+color] = img.data[ipos] as f32;
      ipos += 1;
      opos += 4;
    }
  }

  // Now we go around the image setting the unset colors to the average of the
  // surrounding pixels
  for row in 0..img.height {
    for col in 0..img.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];
      let color = fcol(img, row, col);

      for y in (cmp::max(0,(row as isize)-1) as usize) .. cmp::min(img.height, row+2) {
        for x in (cmp::max(0,(col as isize)-1) as usize) .. cmp::min(img.width, col+2) {
          let c = fcol(img, y, x);
          if c != color {
            sums[c] += img.data[y*img.width+x] as f32;
            counts[c] += 1;
          }
        }
      }

      for c in 0..4 {
        if c != color && counts[c] > 0 {
          out.data[(row*img.width+col)*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }

  out
}

pub fn scaled(img: &Image, scale: usize) -> OpBuffer {
  println!("Scaled demosaic'ing at 1/{} scale", scale);

  let mut out = OpBuffer::new(img.width/scale, img.height/scale, 4);

  // Go around the image averaging every block of pixels
  for row in 0..out.height {
    for col in 0..out.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];

      for y in row*scale..(row+1)*scale {
        for x in col*scale..(col+1)*scale {
          let c = fcol(img, y, x);
          sums[c] += img.data[y*img.width+x] as f32;
          counts[c] += 1;
        }
      }

      for c in 0..4 {
        if counts[c] > 0 {
          out.data[(row*out.width+col)*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }

  out
}
<commit_msg>demosaic: get rid of debug printf<commit_after>use decoders::Image;
use imageops::fcol;
use imageops::OpBuffer;
use std::cmp;

pub fn demosaic_and_scale(img: &Image, minwidth: usize, minheight: usize) -> OpBuffer {
  let scale = cmp::min(img.width / minwidth, img.height / minheight);

  if scale <= 1 {
    full(img)
  } else {
    scaled(img, cmp::min(scale, 16)) // Never go less than 1/16th demosaic
  }
}

pub fn full(img: &Image) -> OpBuffer {
  let mut out = OpBuffer::new(img.width, img.height, 4);

  // First we set the colors we already have
  let mut ipos = 0;
  let mut opos = 0;
  for row in 0..img.height {
    for col in 0..img.width {
      let color = fcol(img, row, col);
      out.data[opos+color] = img.data[ipos] as f32;
      ipos += 1;
      opos += 4;
    }
  }

  // Now we go around the image setting the unset colors to the average of the
  // surrounding pixels
  for row in 0..img.height {
    for col in 0..img.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];
      let color = fcol(img, row, col);

      for y in (cmp::max(0,(row as isize)-1) as usize) .. cmp::min(img.height, row+2) {
        for x in (cmp::max(0,(col as isize)-1) as usize) .. cmp::min(img.width, col+2) {
          let c = fcol(img, y, x);
          if c != color {
            sums[c] += img.data[y*img.width+x] as f32;
            counts[c] += 1;
          }
        }
      }

      for c in 0..4 {
        if c != color && counts[c] > 0 {
          out.data[(row*img.width+col)*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }

  out
}

pub fn scaled(img: &Image, scale: usize) -> OpBuffer {
  let mut out = OpBuffer::new(img.width/scale, img.height/scale, 4);

  // Go around the image averaging every block of pixels
  for row in 0..out.height {
    for col in 0..out.width {
      let mut sums: [f32; 4] = [0.0;4];
      let mut counts: [u32; 4] = [0; 4];

      for y in row*scale..(row+1)*scale {
        for x in col*scale..(col+1)*scale {
          let c = fcol(img, y, x);
          sums[c] += img.data[y*img.width+x] as f32;
          counts[c] += 1;
        }
      }

      for c in 0..4 {
        if counts[c] > 0 {
          out.data[(row*out.width+col)*4+c] = sums[c] / (counts[c] as f32);
        }
      }
    }
  }

  out
}
<|endoftext|>