<commit_before>use std::io::{self,Error,ErrorKind};
use futures::Future;
use futures::future;
use amq_protocol::types::*;
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};
use std::default::Default;

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,
}

#[derive(Clone,Debug,PartialEq)]
pub struct QueueDeclareOptions {
  passive:     bool,
  durable:     bool,
  exclusive:   bool,
  auto_delete: bool,
  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 {
  ticket:    u16,
  exchange:  String,
  mandatory: bool,
  immediate: bool,
}

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

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

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

impl<T: AsyncRead+AsyncWrite+'static> Channel<T> {
  /// creates a queue
  ///
  /// returns a future that resolves once the queue is available
  ///
  /// WARNING: this method cannot pass custom queue_declare arguments yet
  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"))
      ))
    }
  }

  /// publishes a message on a queue
  ///
  /// WARNING: does not handle chunking of the content for now
  pub fn basic_publish(&self, queue: &str, payload: &[u8], options: &BasicPublishOptions) -> Box<Future<Item = (), Error = io::Error>> {
    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(_) => {
          transport.send_frames();
          transport.conn.send_content_frames(self.id, 60, payload);
          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"))
      ))
    }
  }

  /// 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"))
      ))
    }
  }

  /// 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))
      ))
    }
  }
}
<commit_msg>make options members public<commit_after>use std::io::{self,Error,ErrorKind};
use futures::Future;
use futures::future;
use amq_protocol::types::*;
use tokio_io::{AsyncRead,AsyncWrite};
use std::sync::{Arc,Mutex};
use std::default::Default;

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,
}

#[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,
    }
  }
}

#[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,
    }
  }
}

impl<T: AsyncRead+AsyncWrite+'static> Channel<T> {
  /// creates a queue
  ///
  /// returns a future that resolves once the queue is available
  ///
  /// WARNING: this method cannot pass custom queue_declare arguments yet
  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"))
      ))
    }
  }

  /// publishes a message on a queue
  ///
  /// WARNING: does not handle chunking of the content for now
  pub fn basic_publish(&self, queue: &str, payload: &[u8], options: &BasicPublishOptions) -> Box<Future<Item = (), Error = io::Error>> {
    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(_) => {
          transport.send_frames();
          transport.conn.send_content_frames(self.id, 60, payload);
          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"))
      ))
    }
  }

  /// 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"))
      ))
    }
  }

  /// 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))
      ))
    }
  }
}
<|endoftext|>


<commit_before><commit_msg>Make ArgType an enum instead of an i32<commit_after><|endoftext|>


<commit_before>
use super::*;

//

tests_impls!
{
  fn basic_no_args()
  {
    let path = std::ffi::OsStr::new( "../../../target/debug/wtest" );
    let proc = std::process::Command::new( path ).output().unwrap();
    assert!( !proc.status.success() );
    let stderr = std::str::from_utf8( proc.stderr.as_slice() ).unwrap();
    assert!( stderr.contains( "Illformed command \"\"\n" ) );
    let stdout = std::str::from_utf8( proc.stdout.as_slice() ).unwrap();
    assert!( stdout.contains( ".smoke - Perform smoke testing on module." ) );
  }

  //

  /* qqq : make it working */
  // fn basic_with_only_command()
  // {
  //   let path = std::ffi::OsStr::new( "../../../target/debug/wtest" );
  //   let proc = std::process::Command::new( path ).arg( ".smoke " ).output().unwrap();
  //   assert!( !proc.status.success() );
  //   let stdout = std::str::from_utf8( proc.stdout.as_slice() ).unwrap();
  //   assert_eq!( stdout, "Command \".smoke\"\n" );
  //   let stderr = std::str::from_utf8( proc.stderr.as_slice() ).unwrap();
  //   assert!( stderr.contains( "has no file \"Cargo.toml\"" ) );
  // }
}

//

tests_index!
{
  basic_no_args,
  // basic_with_only_command,
}
<commit_msg>Fix tests of utility `wtest`, use compile mode directives<commit_after>
use super::*;

//

tests_impls!
{
  fn basic_no_args()
  {
    #[ cfg( debug_assertions ) ]
    let path = std::ffi::OsStr::new( "../../../target/debug/wtest" );
    #[ cfg( not( debug_assertions ) ) ]
    let path = std::ffi::OsStr::new( "../../../target/release/wtest" );
    let proc = std::process::Command::new( path ).output().unwrap();
    assert!( !proc.status.success() );
    let stderr = std::str::from_utf8( proc.stderr.as_slice() ).unwrap();
    assert!( stderr.contains( "Illformed command \"\"\n" ) );
    let stdout = std::str::from_utf8( proc.stdout.as_slice() ).unwrap();
    assert!( stdout.contains( ".smoke - Perform smoke testing on module." ) );
  }

  //

  /* qqq : make it working */
  // fn basic_with_only_command()
  // {
  //   #[ cfg( debug_assertions ) ]
  //   let path = std::ffi::OsStr::new( "../../../target/debug/wtest" );
  //   #[ cfg( not( debug_assertions ) ) ]
  //   let path = std::ffi::OsStr::new( "../../../target/release/wtest" );
  //   let proc = std::process::Command::new( path ).arg( ".smoke " ).output().unwrap();
  //   assert!( !proc.status.success() );
  //   let stdout = std::str::from_utf8( proc.stdout.as_slice() ).unwrap();
  //   assert_eq!( stdout, "Command \".smoke\"\n" );
  //   let stderr = std::str::from_utf8( proc.stderr.as_slice() ).unwrap();
  //   assert!( stderr.contains( "has no file \"Cargo.toml\"" ) );
  // }
}

//

tests_index!
{
  basic_no_args,
  // basic_with_only_command,
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::cmp::{max, min};
use std::io::Write;
use std::io;
use std::mem;

use rustbox::{RustBox, Key};
use tui::style::Style;
use tui::widget::{Widget, WidgetRet};

static LINEBREAK : char = '\\';

pub struct MsgArea {
    lines  : Vec<Line>,

    width  : i32,
    height : i32,

    /// Total number of lines added to the widget. Note that this is not the
    /// same thing as lines.len(): This simply returns number of lines added to
    /// the widget, rather than number of lines shown by the widget.
    total_lines : i32,

    /// Vertical scroll
    scroll : i32,

    // TODO: logging
}

#[derive(Debug)]
struct Line {
    /// A line. INVARIANT: Not longer than the width of the widget, and shown as
    /// single line in the TUI.
    msg : String,

    /// Is this continuation of previous line?
    continuation : bool,

    /// Index of the line in the buffer. Continuations have same indexes as the
    /// original message.
    line_idx : i32,

    style : Style,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            lines: Vec::new(),
            width: width,
            height: height,
            total_lines: 0,
            scroll: 0,
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Resizing

    fn resize_(&mut self, width : i32, height : i32) {
        // either scroll to bottom ...
        let scroll_to_bottom       = self.need_to_scroll();
        // ... or make sure the first visible line is still visible
        let first_visible_line_idx =
            if self.lines.is_empty() { 0 } else { self.lines[self.scroll as usize].line_idx };

        // Update the size
        self.width = width;
        self.height = height;

        // Combine/re-split lines
        self.resplit_lines();

        // Update the scroll
        if (self.lines.len() as i32) < self.height {
            self.scroll = 0;
        } else if scroll_to_bottom {
            self.scroll = (self.lines.len() as i32) - self.height;
        } else {
            match self.find_line_idx(first_visible_line_idx) {
                None => {/* TODO: Log this somewhere, this is a bug */},
                Some(idx) => { self.scroll = idx as i32; }
            }
        }
    }

    /// Combine continuations with original lines, add lines again in the
    /// original order. Should be called after updating width to have any
    /// effect.
    fn resplit_lines(&mut self) {
        // We could probably modify in-place using two indexes, but whatever.

        let old_lines : Vec<Line> = {
            let total_lines = self.lines.len();
            mem::replace(&mut self.lines, Vec::with_capacity(total_lines))
        };

        let mut line_idx = 0;
        while line_idx < old_lines.len() {
            // How many bytes combined string needs?
            let mut total_len = old_lines[line_idx].msg.len();
            {
                let mut cont_idx  = line_idx + 1;
                while cont_idx < old_lines.len() && old_lines[cont_idx].continuation {
                    total_len += old_lines[cont_idx].msg.len();
                    cont_idx  += 1;
                }
            }

            // Combine all lines
            let mut new_line = String::with_capacity(total_len);
            new_line.push_str(old_lines[line_idx].msg.borrow());
            let mut cont_idx = line_idx + 1;
            while cont_idx < old_lines.len() && old_lines[cont_idx].continuation {
                new_line.push_str(old_lines[cont_idx].msg.borrow());
                cont_idx += 1;
            }

            // Finally add the combined line to the fresh buffer
            self.add_msg_(new_line.chars().collect::<Vec<char>>().borrow(),
                          old_lines[line_idx].style);

            line_idx = cont_idx;
        }
    }

    /// Find index of given line in 'self.lines'.
    fn find_line_idx(&self, line_idx : i32) -> Option<usize> {
        for (line_idx_in_vec, line) in self.lines.iter().enumerate() {
            if line.line_idx == line_idx as i32 {
                return Some(line_idx_in_vec)
            }
        }
        None
    }

    ////////////////////////////////////////////////////////////////////////////

    #[inline]
    pub fn add_msg_str(&mut self, msg_str : &str, style : Style) {
        self.add_msg_str_(msg_str, style)
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &[char], style : Style) {
        self.add_msg_(msg, style)
    }

    fn draw_(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = self.height - 1;
        let mut line_idx = min(self.scroll + self.height, self.lines.len() as i32) - 1;
        while line_idx >= 0 && row >= 0 {
            let line = &self.lines[line_idx as usize];

            if line.continuation {
                rustbox.print_char(pos_x as usize, (pos_y + row) as usize,
                                   line.style.style, line.style.fg, line.style.bg, LINEBREAK);
            }

            let pos_x = if line.continuation { pos_x + 1 } else { pos_x };

            rustbox.print(pos_x as usize, (pos_y + row) as usize,
                          line.style.style, line.style.fg, line.style.bg, &line.msg);

            row -= 1;
            line_idx -= 1;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Adding new messages

    fn add_msg_str_(&mut self, msg : &str, style : Style) {
        // Take the fast path when number of bytes (which gives the max number
        // of characters possibly be in the string) is smaller than the width.
        if msg.len() <= self.width as usize {
            if self.need_to_scroll() {
                self.scroll += 1;
            }

            self.lines.push(Line {
                msg: msg.to_owned(),
                continuation: false,
                line_idx: self.total_lines,
                style: style,
            });

            self.total_lines += 1;
        } else {
            // Need to split the lines, taking the slow path that uses an
            // intermediate vector.
            self.add_msg_(&msg.chars().collect::<Vec<char>>().borrow(), style);
        }
    }

    fn add_msg_(&mut self, mut msg : &[char], style : Style) {
        let mut lines : Vec<Line> = Vec::with_capacity(1);
        while msg.len() != 0 {
            let first_line = lines.len() == 0;
            let split = if first_line { self.width } else { self.width - 1 };

            let (line, rest) = msg.split_at(min(msg.len(), split as usize));
            msg = rest;

            lines.push(Line {
                msg: line.iter().cloned().collect(),
                continuation: !first_line,
                line_idx: self.total_lines,
                style: style,
            });
        }

        // We need to check the scroll before adding the messages, as the check
        // uses current scroll and number of messages.
        if self.need_to_scroll() {
            self.scroll += lines.len() as i32;
        }

        self.lines.append(&mut lines);

        self.total_lines += 1;
    }

    ////////////////////////////////////////////////////////////////////////////

    pub fn scroll_up(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if (self.lines.len() as i32) > self.scroll + self.height {
            self.scroll += 1;
        }
    }

    pub fn page_up(&mut self) {
        self.scroll = max(0, self.scroll - 10);
    }

    pub fn page_down(&mut self) {
        self.scroll = min(self.scroll + 10, (self.lines.len() as i32) - self.height);
    }

    /// Do we need to scroll when adding a new message?
    #[inline]
    fn need_to_scroll(&self) -> bool {
        self.scroll + self.height == self.lines.len() as i32
    }
}

impl Widget for MsgArea {
    fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        self.draw_(rustbox, pos_x, pos_y)
    }

    fn keypressed(&mut self, _ : Key) -> WidgetRet {
        WidgetRet::KeyIgnored
    }

    fn resize(&mut self, width : i32, height : i32) {
        self.resize_(width, height)
    }
}
<commit_msg>warnings<commit_after>use std::borrow::Borrow;
use std::cmp::{max, min};
use std::mem;

use rustbox::{RustBox, Key};
use tui::style::Style;
use tui::widget::{Widget, WidgetRet};

static LINEBREAK : char = '\\';

pub struct MsgArea {
    lines  : Vec<Line>,

    width  : i32,
    height : i32,

    /// Total number of lines added to the widget. Note that this is not the
    /// same thing as lines.len(): This simply returns number of lines added to
    /// the widget, rather than number of lines shown by the widget.
    total_lines : i32,

    /// Vertical scroll
    scroll : i32,

    // TODO: logging
}

#[derive(Debug)]
struct Line {
    /// A line. INVARIANT: Not longer than the width of the widget, and shown as
    /// single line in the TUI.
    msg : String,

    /// Is this continuation of previous line?
    continuation : bool,

    /// Index of the line in the buffer. Continuations have same indexes as the
    /// original message.
    line_idx : i32,

    style : Style,
}

impl MsgArea {
    pub fn new(width : i32, height : i32) -> MsgArea {
        MsgArea {
            lines: Vec::new(),
            width: width,
            height: height,
            total_lines: 0,
            scroll: 0,
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Resizing

    fn resize_(&mut self, width : i32, height : i32) {
        // either scroll to bottom ...
        let scroll_to_bottom       = self.need_to_scroll();
        // ... or make sure the first visible line is still visible
        let first_visible_line_idx =
            if self.lines.is_empty() { 0 } else { self.lines[self.scroll as usize].line_idx };

        // Update the size
        self.width = width;
        self.height = height;

        // Combine/re-split lines
        self.resplit_lines();

        // Update the scroll
        if (self.lines.len() as i32) < self.height {
            self.scroll = 0;
        } else if scroll_to_bottom {
            self.scroll = (self.lines.len() as i32) - self.height;
        } else {
            match self.find_line_idx(first_visible_line_idx) {
                None => {/* TODO: Log this somewhere, this is a bug */},
                Some(idx) => { self.scroll = idx as i32; }
            }
        }
    }

    /// Combine continuations with original lines, add lines again in the
    /// original order. Should be called after updating width to have any
    /// effect.
    fn resplit_lines(&mut self) {
        // We could probably modify in-place using two indexes, but whatever.

        let old_lines : Vec<Line> = {
            let total_lines = self.lines.len();
            mem::replace(&mut self.lines, Vec::with_capacity(total_lines))
        };

        let mut line_idx = 0;
        while line_idx < old_lines.len() {
            // How many bytes combined string needs?
            let mut total_len = old_lines[line_idx].msg.len();
            {
                let mut cont_idx  = line_idx + 1;
                while cont_idx < old_lines.len() && old_lines[cont_idx].continuation {
                    total_len += old_lines[cont_idx].msg.len();
                    cont_idx  += 1;
                }
            }

            // Combine all lines
            let mut new_line = String::with_capacity(total_len);
            new_line.push_str(old_lines[line_idx].msg.borrow());
            let mut cont_idx = line_idx + 1;
            while cont_idx < old_lines.len() && old_lines[cont_idx].continuation {
                new_line.push_str(old_lines[cont_idx].msg.borrow());
                cont_idx += 1;
            }

            // Finally add the combined line to the fresh buffer
            self.add_msg_(new_line.chars().collect::<Vec<char>>().borrow(),
                          old_lines[line_idx].style);

            line_idx = cont_idx;
        }
    }

    /// Find index of given line in 'self.lines'.
    fn find_line_idx(&self, line_idx : i32) -> Option<usize> {
        for (line_idx_in_vec, line) in self.lines.iter().enumerate() {
            if line.line_idx == line_idx as i32 {
                return Some(line_idx_in_vec)
            }
        }
        None
    }

    ////////////////////////////////////////////////////////////////////////////

    #[inline]
    pub fn add_msg_str(&mut self, msg_str : &str, style : Style) {
        self.add_msg_str_(msg_str, style)
    }

    #[inline]
    pub fn add_msg(&mut self, msg : &[char], style : Style) {
        self.add_msg_(msg, style)
    }

    fn draw_(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        let mut row = self.height - 1;
        let mut line_idx = min(self.scroll + self.height, self.lines.len() as i32) - 1;
        while line_idx >= 0 && row >= 0 {
            let line = &self.lines[line_idx as usize];

            if line.continuation {
                rustbox.print_char(pos_x as usize, (pos_y + row) as usize,
                                   line.style.style, line.style.fg, line.style.bg, LINEBREAK);
            }

            let pos_x = if line.continuation { pos_x + 1 } else { pos_x };

            rustbox.print(pos_x as usize, (pos_y + row) as usize,
                          line.style.style, line.style.fg, line.style.bg, &line.msg);

            row -= 1;
            line_idx -= 1;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    // Adding new messages

    fn add_msg_str_(&mut self, msg : &str, style : Style) {
        // Take the fast path when number of bytes (which gives the max number
        // of characters possibly be in the string) is smaller than the width.
        if msg.len() <= self.width as usize {
            if self.need_to_scroll() {
                self.scroll += 1;
            }

            self.lines.push(Line {
                msg: msg.to_owned(),
                continuation: false,
                line_idx: self.total_lines,
                style: style,
            });

            self.total_lines += 1;
        } else {
            // Need to split the lines, taking the slow path that uses an
            // intermediate vector.
            self.add_msg_(&msg.chars().collect::<Vec<char>>().borrow(), style);
        }
    }

    fn add_msg_(&mut self, mut msg : &[char], style : Style) {
        let mut lines : Vec<Line> = Vec::with_capacity(1);
        while msg.len() != 0 {
            let first_line = lines.len() == 0;
            let split = if first_line { self.width } else { self.width - 1 };

            let (line, rest) = msg.split_at(min(msg.len(), split as usize));
            msg = rest;

            lines.push(Line {
                msg: line.iter().cloned().collect(),
                continuation: !first_line,
                line_idx: self.total_lines,
                style: style,
            });
        }

        // We need to check the scroll before adding the messages, as the check
        // uses current scroll and number of messages.
        if self.need_to_scroll() {
            self.scroll += lines.len() as i32;
        }

        self.lines.append(&mut lines);

        self.total_lines += 1;
    }

    ////////////////////////////////////////////////////////////////////////////

    pub fn scroll_up(&mut self) {
        if self.scroll > 0 {
            self.scroll -= 1;
        }
    }

    pub fn scroll_down(&mut self) {
        if (self.lines.len() as i32) > self.scroll + self.height {
            self.scroll += 1;
        }
    }

    pub fn page_up(&mut self) {
        self.scroll = max(0, self.scroll - 10);
    }

    pub fn page_down(&mut self) {
        self.scroll = min(self.scroll + 10, (self.lines.len() as i32) - self.height);
    }

    /// Do we need to scroll when adding a new message?
    #[inline]
    fn need_to_scroll(&self) -> bool {
        self.scroll + self.height == self.lines.len() as i32
    }
}

impl Widget for MsgArea {
    fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        self.draw_(rustbox, pos_x, pos_y)
    }

    fn keypressed(&mut self, _ : Key) -> WidgetRet {
        WidgetRet::KeyIgnored
    }

    fn resize(&mut self, width : i32, height : i32) {
        self.resize_(width, height)
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix lack of increase of congestion window.<commit_after><|endoftext|>


<commit_before><commit_msg>v14: Deprecate radio_show field<commit_after><|endoftext|>


<commit_before>#[macro_use]
extern crate redismodule;
use redismodule::raw;
use redismodule::{RedisResult, RedisValue, Context};
use std::slice;
use redismodule::command::Command;

fn echo(ctx: &Context, args: &[&str]) -> RedisResult {
    return Ok(RedisValue::Array(vec![RedisValue::Integer(1),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd")]));

}

redis_module!("example",
              1,
              vec![Command {
                       name: "hehe",
                       handler: echo,
                       flags: "",
                   }]);
<commit_msg>confusion<commit_after>#[macro_use]
extern crate redismodule;
use redismodule::raw;
use redismodule::{RedisResult, RedisValue, RedisError, Context};
use std::slice;
use redismodule::command::Command;

fn array(ctx: &Context, args: &[&str]) -> RedisResult {
    return Ok(RedisValue::Array(vec![RedisValue::Integer(1),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd"),
                                     RedisValue::String("asd")]));

}

fn wrong_arity(ctx: &Context, args: &[&str]) -> RedisResult {
    Err(RedisError::WrongArity)
}
fn err_msg(ctx: &Context, args: &[&str]) -> RedisResult {
    Err(RedisError::String("sample text"))
}
redis_module!("example",
              1,
              vec![Command {
                       name: "array",
                       handler: array,
                       flags: "",
                   },
                   Command {
                       name: "wrong_arity",
                       handler: wrong_arity,
                       flags: "",
                   },
                   Command {
                       name: "err_msg",
                       handler: err_msg,
                       flags: "",
                   }]);

<|endoftext|>


<commit_before>use clap::{Arg, App};
use std::path::Path;

use inkwell::memory_buffer::MemoryBuffer;
use inkwell::context::Context;
use inkwell::module::Module;

fn main() {
    let matches = App::new("Test inkwell")
        // .version("0.1.0")
        // .author("")
        // .about("")
        .arg(Arg::with_name("output")
                 .short("o")
                 .long("output")
                 .takes_value(true)
                 .help("Output file name"))
        .arg(Arg::with_name("INPUT")
                 .required(true)
                 .index(1)
                 .help("The input file"))
        .get_matches();

    let path_in  = matches.value_of("INPUT").expect("ERROR: missing input file name argument.");
    let path_in  = Path::new(path_in);
    let path_out = matches.value_of("output").unwrap_or("out");
    let path_out = Path::new(path_out);

    let memory_buffer = MemoryBuffer::create_from_file(path_in)
        .expect("ERROR: failed to open file.");
    let context = Context::create();
    let module = context.create_module_from_ir(memory_buffer)
        .expect("ERROR: failed to create module.");
    handle_initializers(&module);
    module.print_to_file(path_out)
        .expect("ERROR: failed to write to file.");
}

////////////////////////////////////////////////////////////////
// Transformations associated with initializers
////////////////////////////////////////////////////////////////

fn handle_initializers(module: &Module) {
    let mut og = module.get_first_global();
    while let Some(g) = og {
        if let Some(s) = g.get_section() {
            if let Ok(s) = s.to_str() {
                if s.starts_with(".init_array") {
                    let i = g.get_initializer().unwrap().into_struct_value();
                    println!("Global name: {} section: {} initializer: {:?}", g.get_name().to_str().unwrap(), s, i)
                }
            }
        }
        og = g.get_next_global();
    }
}

////////////////////////////////////////////////////////////////
// Transformations associated with SeaHorn
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<commit_msg>generate bitcode<commit_after>use clap::{Arg, App};
use std::path::Path;
use std::ffi::OsStr;

use inkwell::memory_buffer::MemoryBuffer;
use inkwell::context::Context;
use inkwell::module::Module;

fn main() {
    // Command line argument parsing (using clap)
    let matches = App::new("Test inkwell")
        // .version("0.1.0")
        // .author("")
        // .about("")
        .arg(Arg::with_name("INPUT")
                 .help("Input file name")
                 .required(true)
                 .index(1))
        .arg(Arg::with_name("OUTPUT")
                 .help("Output file name")
                 .short("o")
                 .long("output")
                 .takes_value(true)
                 .default_value("out"))
        .get_matches();

    let path_in  = matches.value_of("INPUT")
        .expect("ERROR: missing input file name argument.");
    let path_in  = Path::new(path_in);

    let path_out = matches.value_of("OUTPUT")
        .expect("ERROR: missing output file name argument.");
    let path_out = Path::new(path_out);

    let memory_buffer = MemoryBuffer::create_from_file(path_in)
        .expect("ERROR: failed to open file.");

    let context = Context::create();
    let module = context.create_module_from_ir(memory_buffer)
        .expect("ERROR: failed to create module.");

    handle_initializers(&module);

    if path_out.extension() == Some(OsStr::new("bc")) {
        // output bitcode
        module.write_bitcode_to_path(path_out);
    } else {
        // output disassembled bitcode
        // TODO: this function returns bool but the doc doesn't say anything about it.
        module.print_to_file(path_out)
            .expect("ERROR: failed to write to file.");
    }
}

////////////////////////////////////////////////////////////////
// Transformations associated with initializers
////////////////////////////////////////////////////////////////

fn handle_initializers(module: &Module) {
    let mut og = module.get_first_global();
    while let Some(g) = og {
        if let Some(s) = g.get_section() {
            if let Ok(s) = s.to_str() {
                if s.starts_with(".init_array") {
                    let i = g.get_initializer().unwrap().into_struct_value();
                    println!("Global name: {} section: {} initializer: {:?}", g.get_name().to_str().unwrap(), s, i)
                }
            }
        }
        og = g.get_next_global();
    }
}

////////////////////////////////////////////////////////////////
// Transformations associated with SeaHorn
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// End
////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before><commit_msg>Implement `Units` to provide conversion factors between systems of units.<commit_after><|endoftext|>


<commit_before>#![feature(io, path, os, env)]

extern crate nss;

use nss::crypto::pkey;

fn main()
{
    let args = std::env::args().map(|v| v.into_string().unwrap()).collect::<Vec<_>>();
    if args.len() <= 1
    {
        print_usage(&*args[0]);
        return
    }

    let privkey = pkey::RSAPrivateKey::gen(2048).unwrap();
    let pubkey = privkey.get_public().unwrap();

    let pub_der = pubkey.save().unwrap();
    let priv_der = privkey.save().unwrap();

    let priv_path = Path::new(&*args[1]);
    let pub_path = priv_path.with_extension("pub");

    let mut priv_file = std::old_io::File::create(&priv_path).unwrap();
    let mut pub_file = std::old_io::File::create(&pub_path).unwrap();

    println!("pub : {:?}", pub_file.write(&*pub_der));
    println!("priv: {:?}", priv_file.write(&*priv_der));
    let _ = nss::close();
}

fn print_usage(name: &str)
{
    println!("Usage: {} <filename>", name);
}
<commit_msg>Fix os args<commit_after>#![feature(io, path, env)]

extern crate nss;

use nss::crypto::pkey;

fn main()
{
    let args: Vec<_> = std::env::args().collect();
    if args.len() <= 1
    {
        print_usage(&*args[0]);
        return
    }

    let privkey = pkey::RSAPrivateKey::gen(2048).unwrap();
    let pubkey = privkey.get_public().unwrap();

    let pub_der = pubkey.save().unwrap();
    let priv_der = privkey.save().unwrap();

    let priv_path = Path::new(&*args[1]);
    let pub_path = priv_path.with_extension("pub");

    let mut priv_file = std::old_io::File::create(&priv_path).unwrap();
    let mut pub_file = std::old_io::File::create(&pub_path).unwrap();

    println!("pub : {:?}", pub_file.write(&*pub_der));
    println!("priv: {:?}", priv_file.write(&*priv_der));
    let _ = nss::close();
}

fn print_usage(name: &str)
{
    println!("Usage: {} <filename>", name);
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate gfx_text;

use gfx::traits::{Stream, Device};
use gfx_window_glutin as gfxw;
use glutin::{WindowBuilder, Event, VirtualKeyCode, GL_CORE};

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BROWN: [f32; 4] = [0.65, 0.16, 0.16, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const FONT_PATH: &'static str = "examples/assets/Ubuntu-R.ttf";

fn main() {
    env_logger::init().unwrap();

    let (mut stream, mut device, _) = {
        let window = WindowBuilder::new()
            .with_dimensions(640, 480)
            .with_title(format!("gfx_text example"))
            .with_gl(GL_CORE)
            .build()
            .unwrap();
        gfxw::init(window)
    };

    let mut normal_text = gfx_text::new(device.spawn_factory())
        .unwrap();
    let mut big_text = gfx_text::new(device.spawn_factory())
        .with_size(20)
        .unwrap();
    let mut custom_font_text = gfx_text::new(device.spawn_factory())
        .with_size(25)
        .with_font(FONT_PATH)
        .unwrap();

    'main: loop {
        for event in stream.out.window.poll_events() {
            match event {
                Event::Closed => break 'main,
                Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) => break 'main,
                _ => {},
            }
        }
        stream.clear(gfx::ClearData {color: WHITE, depth: 1.0, stencil: 0});

        normal_text.draw("The quick brown fox jumps over the lazy dog", [10, 10], BROWN);
        normal_text.draw("The quick red fox jumps over the lazy dog", [30, 30], RED);
        normal_text.draw_end(&mut stream).unwrap();

        big_text.draw("The big brown fox jumps over the lazy dog", [50, 50], BROWN);
        big_text.draw_end(&mut stream).unwrap();

        custom_font_text.draw("The custom blue fox jumps over the lazy dog", [10, 80], BLUE);
        custom_font_text.draw_end(&mut stream).unwrap();

        //stream.present(&mut device); ICE!
        stream.flush(&mut device);
        stream.out.window.swap_buffers();
        device.cleanup();
    }
}
<commit_msg>Use Stream::present() for the example<commit_after>extern crate env_logger;
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate gfx_text;

use gfx::traits::{Stream, Device};
use gfx_window_glutin as gfxw;
use glutin::{WindowBuilder, Event, VirtualKeyCode, GL_CORE};

const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
const BROWN: [f32; 4] = [0.65, 0.16, 0.16, 1.0];
const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0];
const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0];
const FONT_PATH: &'static str = "examples/assets/Ubuntu-R.ttf";

fn main() {
    env_logger::init().unwrap();

    let (mut stream, mut device, _) = {
        let window = WindowBuilder::new()
            .with_dimensions(640, 480)
            .with_title(format!("gfx_text example"))
            .with_gl(GL_CORE)
            .build()
            .unwrap();
        gfxw::init(window)
    };

    let mut normal_text = gfx_text::new(device.spawn_factory())
        .unwrap();
    let mut big_text = gfx_text::new(device.spawn_factory())
        .with_size(20)
        .unwrap();
    let mut custom_font_text = gfx_text::new(device.spawn_factory())
        .with_size(25)
        .with_font(FONT_PATH)
        .unwrap();

    'main: loop {
        for event in stream.out.window.poll_events() {
            match event {
                Event::Closed => break 'main,
                Event::KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) => break 'main,
                _ => {},
            }
        }
        stream.clear(gfx::ClearData {color: WHITE, depth: 1.0, stencil: 0});

        normal_text.draw("The quick brown fox jumps over the lazy dog", [10, 10], BROWN);
        normal_text.draw("The quick red fox jumps over the lazy dog", [30, 30], RED);
        normal_text.draw_end(&mut stream).unwrap();

        big_text.draw("The big brown fox jumps over the lazy dog", [50, 50], BROWN);
        big_text.draw_end(&mut stream).unwrap();

        custom_font_text.draw("The custom blue fox jumps over the lazy dog", [10, 80], BLUE);
        custom_font_text.draw_end(&mut stream).unwrap();

        stream.present(&mut device);
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_pipeline;
extern crate gfx_device_gl;
extern crate gfx_debug_draw;
extern crate claymore_load;
extern crate claymore_scene; //temp

fn main() {
    use std::env;
    use cgmath::{vec3, FixedArray, Matrix, ToMatrix4, Transform};
    use gfx::traits::*;
    use gfx_pipeline::Pipeline;

    let path = match env::args().nth(1) {
        Some(p) => p,
        None => {
            println!("Call as 'viewer <path_to_scene>`");
            return
        }
    };

    env_logger::init().unwrap();
    println!("Initializing the window...");

    let window = glutin::WindowBuilder::new()
        .with_title("Scene viewer".to_string())
        .with_vsync()
        .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
        .build().unwrap();
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let mut graphics = gfx_device_gl::create(|s| window.get_proc_address(s))
                                    .into_graphics();

    let mut debug_renderer = gfx_debug_draw::DebugRenderer::new(
        &mut graphics, [w, h], 64, None, None).ok().unwrap();

    println!("Loading scene: {}", path);
    let (mut scene, texture) = {
        let mut context = claymore_load::Context::new(&mut graphics.factory,
            env::var("CARGO_MANIFEST_DIR").unwrap_or(".".to_string())
            ).unwrap();
        let scene = context.load_scene(&path).unwrap();
        (scene, (context.texture_black.clone(), None))
    };

    let mut pipeline = gfx_pipeline::forward::Pipeline::<gfx_device_gl::Device>::new(
        &mut graphics.factory, texture).unwrap();
    pipeline.background = Some([0.2, 0.3, 0.4, 1.0]);
    let mut frame = gfx::Frame::new(w as u16, h as u16);

    println!("Rendering...");
    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::Resized(w, h) => {
                    frame.width = w as u16;
                    frame.height = h as u16;
                    debug_renderer.resize(w, h);
                },
                glutin::Event::KeyboardInput(_, _,
                    Some(glutin::VirtualKeyCode::Escape)) =>
                    break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        scene.world.update();
        let mut camera = scene.cameras[0].clone();
        camera.projection.aspect = w as f32 / h as f32;

        for node in scene.world.iter_nodes() {
            let r = node.world.transform_vector(&vec3(0.0, 0.0, 0.0)).into_fixed();
            let x = node.world.transform_vector(&vec3(1.0, 0.0, 0.0)).into_fixed();
            let y = node.world.transform_vector(&vec3(0.0, 1.0, 0.0)).into_fixed();
            let z = node.world.transform_vector(&vec3(0.0, 0.0, 1.0)).into_fixed();
            debug_renderer.draw_line(r, x, [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, y, [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, z, [0.0, 0.0, 1.0, 1.0]);
        }

        let buf = pipeline.render(&scene, &camera, &frame).unwrap();
        graphics.device.submit(buf);

        //debug_renderer.render(&mut graphics, &frame,
        //    camera.get_view_projection(&scene.world));
        {
            use cgmath::FixedArray;
            use claymore_scene::base::World;
            let cam_inv = scene.world.get_transform(&camera.node).invert().unwrap();
            let proj_mx = camera.projection.to_matrix4().mul_m(&cam_inv.to_matrix4()).into_fixed();
            debug_renderer.render(&mut graphics, &frame, proj_mx);
        }

        graphics.end_frame();
        window.swap_buffers();
        graphics.device.after_frame();
    }
    println!("Done.");
}
<commit_msg>Implemented the camera control for the viewer<commit_after>extern crate env_logger;
extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_pipeline;
extern crate gfx_device_gl;
extern crate gfx_debug_draw;
extern crate claymore_load;
extern crate claymore_scene; //temp

type MousePos = (i32, i32);

struct Control {
    rotate_speed: f32,
    zoom_speed: f32,
    base: Option<(MousePos, claymore_scene::Transform<f32>)>,
    last_pos: MousePos,
    space: claymore_scene::Transform<f32>,
}

impl Control {
    pub fn new(rot_speed: f32, zoom_speed: f32,
               space: claymore_scene::Transform<f32>) -> Control {
        Control {
            rotate_speed: rot_speed,
            zoom_speed: zoom_speed,
            base: None,
            last_pos: (0, 0),
            space: space,
        }
    }

    pub fn capture(&mut self, transform: &claymore_scene::Transform<f32>) {
        self.base = Some((self.last_pos, transform.clone()));
    }

    pub fn release(&mut self) {
        self.base = None;
    }

    pub fn position(&mut self, coords: MousePos,
                    transform: &mut claymore_scene::Transform<f32>) {
        self.last_pos = coords;
        match self.base {
            Some((ref base_pos, ref base_transform)) => {
                use cgmath::Transform;
                // p' = Mp * Tc^ * (Tr * Rz * Tr^) * p
                // Tx = (Tr * Rz^ * Tr^) * Tc
                let path = (coords.0 - base_pos.0) as f32 * -self.rotate_speed;
                let rotation = cgmath::Decomposed {
                    scale: 1.0,
                    rot: cgmath::Rotation3::from_axis_angle(
                        &cgmath::vec3(0.0, 0.0, 1.0), cgmath::rad(path)),
                    disp: cgmath::zero(),
                };
                let space_inv = self.space.invert().unwrap();
                let relative = self.space.concat(&rotation.concat(&space_inv));
                *transform = relative.concat(base_transform);
            },
            None => (),
        }
    }

    pub fn wheel(&mut self, shift: i32, transform: &mut claymore_scene::Transform<f32>) {
        use cgmath::{Vector, Transform};
        if self.base.is_some() {
            return
        }
        let vector = transform.transform_vector(&cgmath::vec3(0.0, 0.0, 1.0));
        transform.disp.add_self_v(&vector.mul_s(shift as f32 * -self.zoom_speed));
    }
}

fn main() {
    use std::env;
    use cgmath::{vec3, FixedArray, Matrix, ToMatrix4, Transform};
    use gfx::traits::*;
    use gfx_pipeline::Pipeline;

    let path = match env::args().nth(1) {
        Some(p) => p,
        None => {
            println!("Call as 'viewer <path_to_scene>`");
            return
        }
    };

    env_logger::init().unwrap();
    println!("Initializing the window...");

    let window = glutin::WindowBuilder::new()
        .with_title("Scene viewer".to_string())
        .with_vsync()
        .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
        .build().unwrap();
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let mut graphics = gfx_device_gl::create(|s| window.get_proc_address(s))
                                    .into_graphics();

    let mut debug_renderer = gfx_debug_draw::DebugRenderer::new(
        &mut graphics, [w, h], 64, None, None).ok().unwrap();

    println!("Loading scene: {}", path);
    let (mut scene, texture) = {
        let mut context = claymore_load::Context::new(&mut graphics.factory,
            env::var("CARGO_MANIFEST_DIR").unwrap_or(".".to_string())
            ).unwrap();
        let scene = context.load_scene(&path).unwrap();
        (scene, (context.texture_black.clone(), None))
    };

    let mut pipeline = gfx_pipeline::forward::Pipeline::<gfx_device_gl::Device>::new(
        &mut graphics.factory, texture).unwrap();
    pipeline.background = Some([0.2, 0.3, 0.4, 1.0]);
    let mut frame = gfx::Frame::new(w as u16, h as u16);

    let mut camera = scene.cameras[0].clone();
    camera.projection.aspect = w as f32 / h as f32;
    let mut control = {
        use claymore_scene::base::World;
        let target_node = scene.entities[0].node;
        Control::new(0.005, 0.5, scene.world.get_transform(&target_node))
    };

    println!("Rendering...");
    'main: loop {
        for event in window.poll_events() {
            match event {
                glutin::Event::Resized(w, h) => {
                    frame.width = w as u16;
                    frame.height = h as u16;
                    debug_renderer.resize(w, h);
                },
                glutin::Event::KeyboardInput(_, _,
                    Some(glutin::VirtualKeyCode::Escape)) =>
                    break 'main,
                glutin::Event::Closed => break 'main,
                glutin::Event::MouseInput(glutin::ElementState::Pressed, glutin::MouseButton::Left) =>
                    control.capture(&scene.world.get_node(camera.node).local),
                glutin::Event::MouseInput(glutin::ElementState::Released, glutin::MouseButton::Left) =>
                    control.release(),
                glutin::Event::MouseMoved(coords) =>
                    control.position(coords, &mut scene.world.mut_node(camera.node).local),
                glutin::Event::MouseWheel(shift) =>
                    control.wheel(shift, &mut scene.world.mut_node(camera.node).local),
                _ => {},
            }
        }

        scene.world.update();
        let len = 1f32;

        for node in scene.world.iter_nodes() {
            let r = node.world.transform_vector(&vec3(0.0, 0.0, 0.0)).into_fixed();
            let x = node.world.transform_vector(&vec3(len, 0.0, 0.0)).into_fixed();
            let y = node.world.transform_vector(&vec3(0.0, len, 0.0)).into_fixed();
            let z = node.world.transform_vector(&vec3(0.0, 0.0, len)).into_fixed();
            debug_renderer.draw_line(r, x, [1.0, 0.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, y, [0.0, 1.0, 0.0, 1.0]);
            debug_renderer.draw_line(r, z, [0.0, 0.0, 1.0, 1.0]);
        }

        let buf = pipeline.render(&scene, &camera, &frame).unwrap();
        graphics.device.submit(buf);

        //debug_renderer.render(&mut graphics, &frame,
        //    camera.get_view_projection(&scene.world));
        if true {
            use cgmath::FixedArray;
            use claymore_scene::base::World;
            let cam_inv = scene.world.get_transform(&camera.node).invert().unwrap();
            let proj_mx = camera.projection.to_matrix4().mul_m(&cam_inv.to_matrix4()).into_fixed();
            debug_renderer.render(&mut graphics, &frame, proj_mx);
        }

        graphics.end_frame();
        window.swap_buffers();
        graphics.device.after_frame();
    }
    println!("Done.");
}
<|endoftext|>


<commit_before>// test4.rs
// This test covers the sections:
// - Modules
// - Macros

// Write a macro that passes the test! No hints this time, you can do it!

// I AM NOT DONE

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

    #[test]
    fn test_my_macro() {
        assert_eq!(my_macro!("world!"), "Hello world!");
    }
}

<commit_msg>Add a second test case<commit_after>// test4.rs
// This test covers the sections:
// - Modules
// - Macros

// Write a macro that passes the test! No hints this time, you can do it!

// I AM NOT DONE

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

    #[test]
    fn test_my_macro_world() {
        assert_eq!(my_macro!("world!"), "Hello world!");
    }

    #[test]
    fn test_my_macro_goodbye() {
        assert_eq!(my_macro!("goodbye!"), "Hello goodbye!");
    }
}
<|endoftext|>


<commit_before><commit_msg>Document write_results, even though it is undocumented.<commit_after><|endoftext|>


<commit_before><commit_msg>add Index::from_path_or_cloned_with_options(…) to support different crates repositories<commit_after><|endoftext|>


<commit_before>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::TempDir;
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> Box<File>;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO, create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => {
                        panic!("Failed to create a read buffer to file path: {}", apath.display())
                    }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => {
                        panic!("Failed to create a write buffer to file path: {}", apath.display())
                    }
                }
            }
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    /// Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => { panic!("Unable to read next line. BufferedReader error."); },
        }
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => Box::new(file),
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(&Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    use std::rand;
    let mut path_str = String::from_str("tests/");
    path_str.push_str(rand::random::<usize>().to_string().as_slice());
    path_str.push_str(".txt");
    let path = Path::new(path_str);
    assert!(!path.exists());
    let reader = Reader::new(&path.clone());
    assert!(path.exists());
    fs::unlink(&path);
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

/// Test setup code. Current functions:
/// - Create a new file with `TempDir` and a random name.
/// - Write a 2x2 matrix of records into the base-test.txt file
/// - Returns a tuple of `TempDir` and `Path` to the file.
/// - The path is for r/w access and `TempDir` is so that the directory
///   isn't deleted before the test is completed.
#[allow(dead_code, unused_must_use)]
fn setup() -> (TempDir, Path) {
    use std::rand;
    use std::io::fs;
    use std::io::TempDir;

    let tmpdir = match TempDir::new("txtdb-tests") {
        Ok(dir) => dir,
        Err(..) => panic!("Unable to create test dir in temporary directory."),
    };

    let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

    let mut file = File::create(&final_dir.clone());
    file.write_str("10 11\n20 21\n");

    (tmpdir, final_dir)
}
<commit_msg>Added test for file lock checks<commit_after>extern crate serialize;

use std::io::{File, Open, Append, Read, ReadWrite};
use std::io::TempDir;
use std::io::fs::PathExtensions;
use std::io::{BufferedReader, BufferedWriter};
use std::path::BytesContainer;
use self::serialize::base64::{STANDARD, FromBase64, ToBase64};

/// A result type that's specfici to the Reader module.
/// TODO Decide if this is necessary
pub type ReaderResult<T, E> = Result<T, E>;

/// Reader struct of its basic properties.
pub struct Reader {
    /// Path to file where the Reader is created.
    path: Path,
    /// BufferedReader for reading the file. Initialized with the Path.
    read_buffer: BufferedReader<File>,
    /// BufferedWriter for writing to the file. Initialized with the Path.
    write_buffer: BufferedWriter<File>,
}

/// ReaderFile traits
pub trait ReaderFile {
    // Opens a new File to the Path provided.
    // Returns a boxed File.
    fn open(&self) -> Box<File>;
    // Inserts a string to the database.
    fn insert_string(&mut self, String);
}

impl Reader {
    /// Creates a new Reader from the Path provided.
    /// Opens a new BufferedReader and BufferedWriter (with Append mode) to the file.
    /// If the file doesn't exist, it is created.
    // TODO, create a .lock file to let other readers know the database is in use (see: #2).
    pub fn new(apath: &Path) -> Reader {
        Reader {
            path: {
                if !apath.exists() { File::create(&apath.clone()); }
                apath.clone()
            },
            read_buffer: {
                match File::open_mode(&apath.clone(), Open, Read) {
                    Ok(file)    => { BufferedReader::new(file) },
                    Err(..)     => {
                        panic!("Failed to create a read buffer to file path: {}", apath.display())
                    }
                }
            },
            write_buffer: {
                match File::open_mode(&apath.clone(), Append, ReadWrite) {
                    Ok(file)    => { BufferedWriter::new(file) },
                    Err(..)     => {
                        panic!("Failed to create a write buffer to file path: {}", apath.display())
                    }
                }
            }
        }
    }

    /// This is a helder function that realistically shouldn't exist in production.
    /// Used primarily for "spilling" the entire database file into a Vec<String>
    fn spill(&mut self) -> Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for line_iter in self.read_buffer.lines() {
            result.push(line_iter.unwrap().trim().to_string());
        }
        return result;
    }

    /// Inserts a &str into the database.
    fn insert_str(&mut self, item: &str) {
        self.write_buffer.write_line(item);
        self.write_buffer.flush();
    }

    /// Inserts a byte array into the database.
    fn insert(&mut self, item: &[u8]) {
        self.write_buffer.write(item);
        self.write_buffer.flush();
    }

    /// Read a &str from the database
    fn read_line(&mut self) -> String {
        match self.read_buffer.read_line() {
            Ok(string)  => { string.to_string() },
            Err(..)     => { panic!("Unable to read next line. BufferedReader error."); },
        }
    }

}

impl ReaderFile for Reader {

    fn open(&self) -> Box<File> {
        match File::open_mode(&self.path, Open, ReadWrite) {
            Ok(file)    => Box::new(file),
            Err(..)     => { panic!("File {} couldn't be opened!", &self.path.display()); },
        }
    }

    fn insert_string(&mut self, item: String) {
        self.insert_str(item.as_slice());
    }

}

#[test]
fn test_open_file() {
    let reader = Reader::new(&Path::new("tests/base-test.txt"));
}

#[test]
fn test_create_file() {
    use std::io::fs;
    use std::io::fs::PathExtensions;
    use std::rand;
    let mut path_str = String::from_str("tests/");
    path_str.push_str(rand::random::<usize>().to_string().as_slice());
    path_str.push_str(".txt");
    let path = Path::new(path_str);
    assert!(!path.exists());
    let reader = Reader::new(&path.clone());
    assert!(path.exists());
    fs::unlink(&path);
}

#[test]
fn test_read_file() {
    // We should output the entire contents of the database file we open
    // into standard output.
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string()];
    assert_eq!(expected, reader.spill());
}

#[test]
fn test_write_string_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_string("30 31".to_string());
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_write_str_to_file() {
    let (tempdir, path) = setup();
    let mut reader = Reader::new(&path);
    let expected = vec!["10 11".to_string(), "20 21".to_string(), "30 31".to_string()];
    reader.insert_str("30 31");
    assert_eq![expected, reader.spill()];
}

#[test]
fn test_file_path_lock() {
    use std::str;

    let (tempdir, path) = setup();
    let mut expected = path.clone();
    expected.pop();

    // Surely, there's a less ugly way to take the filename of a Path and convert it to a string?!
    let mut filename_lock: String = str::from_utf8(path.filename().unwrap()).unwrap().to_string();
    filename_lock.push_str(".lock");
    let expected_filelock_path = expected.join(filename_lock);

    let reader = Reader::new(&path);

    assert!(expected_filelock_path.exists() && expected_filelock_path.is_file());
}

/// Test setup code. Current functions:
/// - Create a new file with `TempDir` and a random name.
/// - Write a 2x2 matrix of records into the base-test.txt file
/// - Returns a tuple of `TempDir` and `Path` to the file.
/// - The path is for r/w access and `TempDir` is so that the directory
///   isn't deleted before the test is completed.
#[allow(dead_code, unused_must_use)]
fn setup() -> (TempDir, Path) {
    use std::rand;
    use std::io::fs;
    use std::io::TempDir;

    let tmpdir = match TempDir::new("txtdb-tests") {
        Ok(dir) => dir,
        Err(..) => panic!("Unable to create test dir in temporary directory."),
    };

    let final_dir = tmpdir.path().join(rand::random::<usize>().to_string());

    let mut file = File::create(&final_dir.clone());
    file.write_str("10 11\n20 21\n");

    (tmpdir, final_dir)
}
<|endoftext|>


<commit_before><commit_msg>Don't hang when clicking outside file bounds<commit_after><|endoftext|>


<commit_before>use bus::Addressable;
use enum_primitive::FromPrimitive;

const ADDR_DIV: u16  = 0xFF04;
const ADDR_TIMA: u16 = 0xFF05;
const ADDR_TMA: u16  = 0xFF06;
const ADDR_TAC: u16  = 0xFF07;

enum_from_primitive! {
    #[derive(Copy, Clone)]
    enum TacFrequency {
        Khz4 = 0,
        Khz262 = 1,
        Khz65 = 2,
        Khz16 = 3
    }
}

impl TacFrequency {
    fn as_cycles(&self) -> usize {
        match *self {
            TacFrequency::Khz4 => 1024,
            TacFrequency::Khz262 => 16,
            TacFrequency::Khz65 => 64,
            TacFrequency::Khz16 => 256
        }
    }
}

#[derive(Default)]
pub struct TimerResult {
    pub interrupt: bool
}

pub struct Timer {
    div: u16,
    tima: u8,
    tma: u8,
    tac_enabled: bool,
    tac_freq: TacFrequency,
    tac_counter: usize
}

impl Timer {
    pub fn new() -> Self {
        Self {
            div: 0xABCC,
            tima: 0,
            tma: 0,
            tac_enabled: false,
            tac_freq: TacFrequency::Khz4,
            tac_counter: 0
        }
    }

    // TODO: implement odd Timer behaviors
    pub fn step(&mut self, cycles: usize) -> TimerResult {
        let mut result = TimerResult::default();

        // DIV always counts at a constant interval even if the timer is disabled
        self.div = self.div.wrapping_add(cycles as u16);

        // TIMA counts if TAC is enabled. It counts at an interval set by TAC.
        if self.tac_enabled {
            self.tac_counter = self.tac_counter + cycles;
            if self.tac_counter >= self.tac_freq.as_cycles() {
                let previous = self.tima;
                self.tima = self.tima.wrapping_add(1);

                // When TIMA overflows, it is reset to TMA and an interrupt is raised.
                if previous > self.tima {
                    self.tima = self.tma;
                    self.tac_counter = 0;
                    result.interrupt = true;
                }
            }
        }

        result
    }
}

impl Addressable for Timer {
    fn read(&self, addr: u16) -> u8 {
        match addr {
            ADDR_DIV => (self.div >> 8) as u8, // Retrieving DIV only returns the MSB,
            ADDR_TIMA => self.tima,
            ADDR_TMA => self.tma,
            ADDR_TAC => 0b1111_1000 | ((self.tac_enabled as u8) << 2) | (self.tac_freq as u8),
            _ => { println!("Timer read unimplemented ({:#X})", addr); 0 }
        }
    }

    fn write(&mut self, addr: u16, val: u8) {
        match addr {
            // Writing any value to DIV resets it to 0
            ADDR_DIV => self.div = 0,
            ADDR_TIMA => self.tima = val,
            ADDR_TMA => self.tima = val,
            ADDR_TAC => {
                self.tac_enabled = (val & 0b100) == 0b100;
                self.tac_freq = TacFrequency::from_u8(val & 0b11).unwrap();
            },
            _ => println!("Timer write unimplemented {:#X} -> {:#X}", val, addr)
        }
    }
}<commit_msg>Timer fixes<commit_after>use bus::Addressable;
use enum_primitive::FromPrimitive;

const ADDR_DIV: u16  = 0xFF04;
const ADDR_TIMA: u16 = 0xFF05;
const ADDR_TMA: u16  = 0xFF06;
const ADDR_TAC: u16  = 0xFF07;

enum_from_primitive! {
    #[derive(Copy, Clone)]
    enum TacFrequency {
        Khz4 = 0,
        Khz262 = 1,
        Khz65 = 2,
        Khz16 = 3
    }
}

impl TacFrequency {
    fn as_cycles(&self) -> usize {
        match *self {
            TacFrequency::Khz4 => 1024,
            TacFrequency::Khz16 => 256,
            TacFrequency::Khz65 => 64,
            TacFrequency::Khz262 => 16
        }
    }
}

#[derive(Default)]
pub struct TimerResult {
    pub interrupt: bool
}

pub struct Timer {
    div: u16,
    tima: u8,
    tma: u8,
    tac_enabled: bool,
    tac_freq: TacFrequency,

    div_counter: usize,
    tima_counter: usize
}

impl Timer {
    pub fn new() -> Self {
        Self {
            div: 0xABCC,
            tima: 0,
            tma: 0,
            tac_enabled: false,
            tac_freq: TacFrequency::Khz4,
            div_counter: 0,
            tima_counter: 0
        }
    }

    // TODO: implement odd Timer behaviors
    pub fn step(&mut self, cycles: usize) -> TimerResult {
        let mut result = TimerResult::default();

        // DIV always counts at a constant interval even if the timer is disabled
        // DIV increments once every ~256 machine cycles
        self.div_counter += cycles;

        if self.div_counter >= 256 {
            self.div = self.div.wrapping_add(1);
            self.div_counter -= 256;
        }

        // TIMA counts if TAC is enabled. It counts at an interval set by TAC.
        if self.tac_enabled {
            self.tima_counter += cycles;

            let tac_cycles = self.tac_freq.as_cycles();

            if self.tima_counter >= tac_cycles {
                // When TIMA overflows, it is reset to TMA and an interrupt is raised.
                if self.tima == 0xFF {
                    self.tima = self.tma;
                    result.interrupt = true;
                } else {
                    self.tima += 1;
                }

                self.tima_counter -= tac_cycles;
            }
        }

        result
    }
}

impl Addressable for Timer {
    fn read(&self, addr: u16) -> u8 {
        match addr {
            ADDR_DIV => (self.div >> 8) as u8, // Retrieving DIV only returns the MSB,
            ADDR_TIMA => self.tima,
            ADDR_TMA => self.tma,
            ADDR_TAC => 0b1111_1000 | ((self.tac_enabled as u8) << 2) | (self.tac_freq as u8),
            _ => { println!("Timer read unimplemented ({:#X})", addr); 0 }
        }
    }

    fn write(&mut self, addr: u16, val: u8) {
        match addr {
            // Writing any value to DIV resets it to 0
            ADDR_DIV => self.div = 0,
            ADDR_TIMA => self.tima = val,
            ADDR_TMA => self.tma = val,
            ADDR_TAC => {
                self.tac_enabled = (val & 0b100) == 0b100;
                self.tac_freq = TacFrequency::from_u8(val & 0b11).unwrap();
            },
            _ => println!("Timer write unimplemented {:#X} -> {:#X}", val, addr)
        }
    }
}<|endoftext|>


<commit_before><commit_msg>Split overly long lines<commit_after><|endoftext|>


<commit_before>use self::super::{ERR_HOST, ERR_HTSI, ERR_INVALID, MAP, OK};
use self::super::super::http;

use std::u16;

pub fn init(ctn: u16, pn: u16) -> i8 {
    let checked_ctn = match ctn {
        ctn if ctn >= u16::MIN && ctn <= u16::MAX => ctn,
        _ => {
            error!("ctn is not an u16!. Returning {}", ERR_INVALID);
            return ERR_INVALID;
        }
    };

    let checked_pn = match pn {
        pn if pn >= u16::MIN && pn <= u16::MAX => pn,
        _ => {
            error!("pn is not an u16!. Returning {}", ERR_INVALID);
            return ERR_INVALID;
        }
    };

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&checked_ctn) {
        error!("Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Build the request URL
    let path = get_request_path(checked_ctn, checked_pn);

    // Perform the request
    let http_response = match http::simple_post(path) {
        Ok(http_response) => http_response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    let (http_status, response_body) = http::extract_response(http_response);
    match http_status {
        http::HttpStatus::Ok => handle_ok_status(response_body, checked_ctn, checked_pn),
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn get_request_path(ctn: u16, pn: u16) -> String {
    let mut path = String::from("ct_init");
    path.push_str("/");
    path.push_str(&ctn.to_string());
    path.push_str("/");
    path.push_str(&pn.to_string());

    path
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> i8 {
    let status = body.parse::<i8>().unwrap();
    if status == OK {
        // Store CTN
        MAP.lock().unwrap().insert(ctn, pn);
        debug!("Card terminal opened.");
    }

    debug!("Returning {}", status);
    status
}
<commit_msg>use format to build ct_init path<commit_after>use self::super::{ERR_HOST, ERR_HTSI, ERR_INVALID, MAP, OK};
use self::super::super::http;

use std::u16;

pub fn init(ctn: u16, pn: u16) -> i8 {
    let checked_ctn = match ctn {
        ctn if ctn >= u16::MIN && ctn <= u16::MAX => ctn,
        _ => {
            error!("ctn is not an u16!. Returning {}", ERR_INVALID);
            return ERR_INVALID;
        }
    };

    let checked_pn = match pn {
        pn if pn >= u16::MIN && pn <= u16::MAX => pn,
        _ => {
            error!("pn is not an u16!. Returning {}", ERR_INVALID);
            return ERR_INVALID;
        }
    };

    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&checked_ctn) {
        error!("Card terminal has already been opened. Returning {}",
               ERR_INVALID);
        return ERR_INVALID;
    }

    // Perform the request
    let path = format!("ct_init/{}/{}", checked_ctn, checked_pn);
    let http_response = match http::simple_post(path) {
        Ok(http_response) => http_response,
        Err(error) => {
            debug!("Error: {:?}", error);
            error!("Request failed! Returning {}", ERR_HTSI);
            return ERR_HTSI;
        }
    };

    let (http_status, response_body) = http::extract_response(http_response);
    match http_status {
        http::HttpStatus::Ok => handle_ok_status(response_body, checked_ctn, checked_pn),
        _ => {
            error!("Response not OK! Returning {}", ERR_HOST);
            ERR_HOST
        }
    }
}

fn handle_ok_status(body: String, ctn: u16, pn: u16) -> i8 {
    let status = body.parse::<i8>().unwrap();
    if status == OK {
        // Store CTN
        MAP.lock().unwrap().insert(ctn, pn);
        debug!("Card terminal opened.");
    }

    debug!("Returning {}", status);
    status
}
<|endoftext|>


<commit_before>use nalgebra;
use num::Num;
use std::cmp;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

pub trait ClampedRange {
    type Output;

    fn max_value() -> Self::Output;
    fn min_value() -> Self::Output;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()), PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn unclamped(&self) -> T {
        self.0
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T> {}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> cmp::Eq for Clamped<T, R>
    where T: Copy + cmp::Eq + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T> {}

impl<T, R> cmp::Ord for Clamped<T, R>
    where T: Copy + Num + cmp::Ord + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> cmp::PartialEq for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> cmp::PartialOrd for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<Output = T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<commit_msg>Remove associated type from `ClampedRange`.<commit_after>use nalgebra;
use num::Num;
use std::cmp;
use std::convert::From;
use std::marker::PhantomData;
use std::ops;

pub trait ClampedRange<T> {
    fn max_value() -> T;
    fn min_value() -> T;
}

pub struct Clamped<T, R>(T, PhantomData<R>)
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>;

impl<T, R> Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    pub fn new(value: T) -> Self {
        Clamped(nalgebra::clamp(value, R::min_value(), R::max_value()), PhantomData)
    }

    pub fn max_value() -> Self {
        Clamped(R::max_value(), PhantomData)
    }

    pub fn min_value() -> Self {
        Clamped(R::min_value(), PhantomData)
    }

    pub fn unclamped(&self) -> T {
        self.0
    }
}

impl<T, R> Clone for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn clone(&self) -> Self {
        Clamped(self.0, PhantomData)
    }
}

impl<T, R> Copy for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> From<T> for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T, R> cmp::Eq for Clamped<T, R>
    where T: Copy + cmp::Eq + Num + cmp::PartialOrd,
          R: ClampedRange<T> {}

impl<T, R> cmp::Ord for Clamped<T, R>
    where T: Copy + Num + cmp::Ord + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl<T, R> cmp::PartialEq for Clamped<T, R>
    where T: Copy + Num + cmp::PartialEq + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }
}

impl<T, R> cmp::PartialOrd for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<T, R> ops::Add for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0.add(other.0))
    }
}

impl<T, R> ops::Add<T> for Clamped<T, R>
    where T: ops::Add<Output = T> + Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn add(self, other: T) -> Self::Output {
        Self::new(self.0.add(other))
    }
}

impl<T, R> ops::Deref for Clamped<T, R>
    where T: Copy + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T, R> ops::Div for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: Self) -> Self::Output {
        Self::new(self.0.div(other.0))
    }
}

impl<T, R> ops::Div<T> for Clamped<T, R>
    where T: Copy + ops::Div<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn div(self, other: T) -> Self::Output {
        Self::new(self.0.div(other))
    }
}

impl<T, R> ops::Mul for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: Self) -> Self::Output {
        Self::new(self.0.mul(other.0))
    }
}

impl<T, R> ops::Mul<T> for Clamped<T, R>
    where T: Copy + ops::Mul<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn mul(self, other: T) -> Self::Output {
        Self::new(self.0.mul(other))
    }
}

impl<T, R> ops::Neg for Clamped<T, R>
    where T: Copy + ops::Neg<Output = T> + Num + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn neg(self) -> Self::Output {
        Self::new(self.0.neg())
    }
}

impl<T, R> ops::Sub for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: Self) -> Self::Output {
        Self::new(self.0.sub(other.0))
    }
}

impl<T, R> ops::Sub<T> for Clamped<T, R>
    where T: Copy + Num + ops::Sub<Output = T> + cmp::PartialOrd,
          R: ClampedRange<T>
{
    type Output = Self;

    fn sub(self, other: T) -> Self::Output {
        Self::new(self.0.sub(other))
    }
}
<|endoftext|>


<commit_before>use nalgebra::Pnt3;
use range_abs::range_abs;

#[cfg(test)]
use std::collections::HashSet;
#[cfg(test)]
use test::Bencher;

#[inline]
/// Generate the set of points corresponding to the surface of a cube made of voxels.
pub fn cube_shell(center: &Pnt3<int>, radius: int) -> Vec<Pnt3<int>> {
  let mut shell = Vec::new();

  macro_rules! add_square(
    ($dxs: expr, $dys: expr, $dzs: expr) => (
      for dx in $dxs {
        for dy in $dys {
          for dz in $dzs {
            shell.push(Pnt3::new(
              center.x + dx,
              center.y + dy,
              center.z + dz,
            ));
          }
        }
      }
    );
  );

  add_square!(
    [-radius, radius].iter().map(|&dx| dx),
    range_abs(radius),
    range_abs(radius)
  );
  add_square!(
    range_abs(radius - 1),
    [-radius, radius].iter().map(|&dy| dy),
    range_abs(radius)
  );
  add_square!(
    range_abs(radius - 1),
    range_abs(radius - 1),
    [-radius, radius].iter().map(|&dz| dz)
  );

  shell
}

#[cfg(test)]
/// the number of elements in a cube shell
pub fn cube_shell_area(radius: int) -> uint {
  assert!(radius >= 0);
  if radius == 0 {
    return 1;
  }

  let width = 2 * radius + 1;
  // volume of the cube
  let outer = width * width * width;
  // volume of the cube of radius r - 1.
  let inner = (width - 2) * (width - 2) * (width - 2);
  (outer - inner) as uint
}

#[test]
// Check that the surface area is correct for a few different shells.
fn test_surface_area() {
  let centers = [
    Pnt3::new(0, 0, 0),
    Pnt3::new(2, 1, -4),
  ];
  for center in centers.iter() {
    for radius in range(1, 5) {
      assert_eq!(
        cube_shell(center.clone(), radius as int).len(),
        cube_shell_area(radius)
      );
    }
  }
}

#[test]
fn test_simple_shell() {
  let center = Pnt3::new(2, 0, -3);
  let radius = 1;

  let expected: HashSet<Pnt3<int>> = [
      Pnt3::new( 0,  0,  1),
      Pnt3::new( 0,  0, -1),
      Pnt3::new( 0,  1,  0),
      Pnt3::new( 0,  1,  1),
      Pnt3::new( 0,  1, -1),
      Pnt3::new( 0, -1,  0),
      Pnt3::new( 0, -1,  1),
      Pnt3::new( 0, -1, -1),
      Pnt3::new( 1,  0,  0),
      Pnt3::new( 1,  0,  1),
      Pnt3::new( 1,  0, -1),
      Pnt3::new( 1,  1,  0),
      Pnt3::new( 1,  1,  1),
      Pnt3::new( 1,  1, -1),
      Pnt3::new( 1, -1,  0),
      Pnt3::new( 1, -1,  1),
      Pnt3::new( 1, -1, -1),
      Pnt3::new(-1,  0,  0),
      Pnt3::new(-1,  0,  1),
      Pnt3::new(-1,  0, -1),
      Pnt3::new(-1,  1,  0),
      Pnt3::new(-1,  1,  1),
      Pnt3::new(-1,  1, -1),
      Pnt3::new(-1, -1,  0),
      Pnt3::new(-1, -1,  1),
      Pnt3::new(-1, -1, -1),
    ]
    .iter()
    .map(|p| p.clone() + center.to_vec())
    .collect();

  assert_eq!(expected, cube_shell(center, radius).into_iter().collect());
}

#[bench]
fn simple_bench(_: &mut Bencher) {
  let _ = cube_shell(Pnt3::new(0, 0, 0), 100);
}
<commit_msg>fix tests<commit_after>use nalgebra::Pnt3;
use range_abs::range_abs;

#[cfg(test)]
use std::collections::HashSet;
#[cfg(test)]
use test::Bencher;

#[inline]
/// Generate the set of points corresponding to the surface of a cube made of voxels.
pub fn cube_shell(center: &Pnt3<int>, radius: int) -> Vec<Pnt3<int>> {
  let mut shell = Vec::new();

  macro_rules! add_square(
    ($dxs: expr, $dys: expr, $dzs: expr) => (
      for dx in $dxs {
        for dy in $dys {
          for dz in $dzs {
            shell.push(Pnt3::new(
              center.x + dx,
              center.y + dy,
              center.z + dz,
            ));
          }
        }
      }
    );
  );

  add_square!(
    [-radius, radius].iter().map(|&dx| dx),
    range_abs(radius),
    range_abs(radius)
  );
  add_square!(
    range_abs(radius - 1),
    [-radius, radius].iter().map(|&dy| dy),
    range_abs(radius)
  );
  add_square!(
    range_abs(radius - 1),
    range_abs(radius - 1),
    [-radius, radius].iter().map(|&dz| dz)
  );

  shell
}

#[cfg(test)]
/// the number of elements in a cube shell
pub fn cube_shell_area(radius: int) -> uint {
  assert!(radius >= 0);
  if radius == 0 {
    return 1;
  }

  let width = 2 * radius + 1;
  // volume of the cube
  let outer = width * width * width;
  // volume of the cube of radius r - 1.
  let inner = (width - 2) * (width - 2) * (width - 2);
  (outer - inner) as uint
}

#[test]
// Check that the surface area is correct for a few different shells.
fn test_surface_area() {
  let centers = [
    Pnt3::new(0, 0, 0),
    Pnt3::new(2, 1, -4),
  ];
  for center in centers.iter() {
    for radius in range(1, 5) {
      assert_eq!(
        cube_shell(center, radius as int).len(),
        cube_shell_area(radius)
      );
    }
  }
}

#[test]
fn test_simple_shell() {
  let center = Pnt3::new(2, 0, -3);
  let radius = 1;

  let expected: HashSet<Pnt3<int>> = [
      Pnt3::new( 0,  0,  1),
      Pnt3::new( 0,  0, -1),
      Pnt3::new( 0,  1,  0),
      Pnt3::new( 0,  1,  1),
      Pnt3::new( 0,  1, -1),
      Pnt3::new( 0, -1,  0),
      Pnt3::new( 0, -1,  1),
      Pnt3::new( 0, -1, -1),
      Pnt3::new( 1,  0,  0),
      Pnt3::new( 1,  0,  1),
      Pnt3::new( 1,  0, -1),
      Pnt3::new( 1,  1,  0),
      Pnt3::new( 1,  1,  1),
      Pnt3::new( 1,  1, -1),
      Pnt3::new( 1, -1,  0),
      Pnt3::new( 1, -1,  1),
      Pnt3::new( 1, -1, -1),
      Pnt3::new(-1,  0,  0),
      Pnt3::new(-1,  0,  1),
      Pnt3::new(-1,  0, -1),
      Pnt3::new(-1,  1,  0),
      Pnt3::new(-1,  1,  1),
      Pnt3::new(-1,  1, -1),
      Pnt3::new(-1, -1,  0),
      Pnt3::new(-1, -1,  1),
      Pnt3::new(-1, -1, -1),
    ]
    .iter()
    .map(|p| p.clone() + center.to_vec())
    .collect();

  assert_eq!(expected, cube_shell(&center, radius).into_iter().collect());
}

#[bench]
fn simple_bench(_: &mut Bencher) {
  let _ = cube_shell(&Pnt3::new(0, 0, 0), 100);
}
<|endoftext|>