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

//! Single-threaded TCP echo server with a bounded buffer pool. Allocates N buffers upon
//! initialization and uses them to serve up to N clients concurrently. When all buffers are in use,
//! the server waits until the next buffer becomes available before accepting the next client
//! connection.

extern crate gj;
extern crate gjio;

use gj::{EventLoop, Promise, PromiseFulfiller, TaskReaper, TaskSet};
use gjio::{AsyncRead, AsyncWrite, BufferPrefix};
use std::cell::RefCell;
use std::rc::Rc;

/// Container for buffers that are not currently being used on a connection.
struct BufferPool {
    buffers: Vec<Vec<u8>>,
    waiting: Option<PromiseFulfiller<Buffer, ::std::io::Error>>,
}

impl BufferPool {
    pub fn new(buf_size: usize, num_buffers: usize) -> BufferPool {
        BufferPool { buffers: vec![vec![0; buf_size]; num_buffers], waiting: None }
    }

    /// Retrieves a buffer from the pool, waiting until one is available if there are none
    /// already available. Fails if another task is already waiting for a buffer.
    pub fn pop(pool: &Rc<RefCell<BufferPool>>) -> Promise<Buffer, ::std::io::Error> {
        let &mut BufferPool { ref mut buffers, ref mut waiting } = &mut *pool.borrow_mut();
        match buffers.pop() {
            Some(buf) => Promise::ok(Buffer { buf: buf, pool: pool.clone() }),
            None => {
                if waiting.is_some() {
                    Promise::err(::std::io::Error::new(::std::io::ErrorKind::Other,
                                                       "another client is already waiting"))
                } else {
                    let (promise, fulfiller) = Promise::and_fulfiller();
                    *waiting = Some(fulfiller);
                    promise
                }
            }
        }
    }

    pub fn push(pool: &Rc<RefCell<BufferPool>>, buf: Vec<u8>) {
        let waiting = pool.borrow_mut().waiting.take();
        match waiting {
            Some(fulfiller) => fulfiller.fulfill(Buffer { buf: buf, pool: pool.clone() }),
            None => pool.borrow_mut().buffers.push(buf),
        }
    }
}

// A buffer borrowed from a BufferPool. When a Buffer dropped, its storage is returned to the pool.
struct Buffer {
    buf: Vec<u8>,
    pool: Rc<RefCell<BufferPool>>,
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let buf = ::std::mem::replace(&mut self.buf, Vec::with_capacity(0));
        BufferPool::push(&self.pool, buf);
    }
}

impl AsRef<[u8]> for Buffer {
    fn as_ref<'a>(&'a self) -> &'a [u8] { &self.buf[..] }
}

impl AsMut<[u8]> for Buffer {
    fn as_mut<'a>(&'a mut self) -> &'a mut [u8] { &mut self.buf[..] }
}

/// Reads `buf`-sized chunks of bytes from a stream until end-of-file, immediately writing each
/// chunk back to the same stream. Note that this function is recursive. In a naive implementation
/// of promises, such a function could potentially create an unbounded chain of promises. However,
/// GJ implements a tail-call optimization that shortens promise chains when possible, and therefore
/// this loop can run indefinitely, consuming only a small, bounded amount of memory.
fn echo(mut stream: gjio::SocketStream, buf: Buffer) -> Promise<(), ::std::io::Error> {
    stream.try_read(buf, 1).then(move |(buf, n)| {
        if n == 0 { // EOF
            Promise::ok(())
        } else {
            stream.write(BufferPrefix::new(buf, n)).then(move |prefix| {
                echo(stream, prefix.buf)
            })
        }
    })
}

struct Reaper;

impl TaskReaper<(), ::std::io::Error> for Reaper {
    fn task_failed(&mut self, error: ::std::io::Error) {
        println!("Task failed: {}", error);
    }
}

/// Waits for a buffer from the pool, accepts a connection, then spawns an echo() task on that
/// connection with that buffer.
fn accept_loop(listener: gjio::SocketListener,
               mut task_set: TaskSet<(), ::std::io::Error>,
               buffer_pool: Rc<RefCell<BufferPool>>)
               -> Promise<(), ::std::io::Error>
{
    BufferPool::pop(&buffer_pool).then(move |buf| {
        listener.accept().then(move |stream| {
            task_set.add(echo(stream, buf));
            accept_loop(listener, task_set, buffer_pool)
        })
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return;
    }
    let buffer_pool = Rc::new(RefCell::new(BufferPool::new(1024, 64)));

    EventLoop::top_level(move |wait_scope| -> Result<(), ::std::io::Error> {
        use std::net::ToSocketAddrs;
        let mut event_port = try!(gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());
        let reaper = Box::new(Reaper);
        accept_loop(listener, TaskSet::new(reaper), buffer_pool).lift().wait(wait_scope, &mut event_port)
    }).expect("top level");
}
<commit_msg>remove redundant lift() call<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! Single-threaded TCP echo server with a bounded buffer pool. Allocates N buffers upon
//! initialization and uses them to serve up to N clients concurrently. When all buffers are in use,
//! the server waits until the next buffer becomes available before accepting the next client
//! connection.

extern crate gj;
extern crate gjio;

use gj::{EventLoop, Promise, PromiseFulfiller, TaskReaper, TaskSet};
use gjio::{AsyncRead, AsyncWrite, BufferPrefix};
use std::cell::RefCell;
use std::rc::Rc;

/// Container for buffers that are not currently being used on a connection.
struct BufferPool {
    buffers: Vec<Vec<u8>>,
    waiting: Option<PromiseFulfiller<Buffer, ::std::io::Error>>,
}

impl BufferPool {
    pub fn new(buf_size: usize, num_buffers: usize) -> BufferPool {
        BufferPool { buffers: vec![vec![0; buf_size]; num_buffers], waiting: None }
    }

    /// Retrieves a buffer from the pool, waiting until one is available if there are none
    /// already available. Fails if another task is already waiting for a buffer.
    pub fn pop(pool: &Rc<RefCell<BufferPool>>) -> Promise<Buffer, ::std::io::Error> {
        let &mut BufferPool { ref mut buffers, ref mut waiting } = &mut *pool.borrow_mut();
        match buffers.pop() {
            Some(buf) => Promise::ok(Buffer { buf: buf, pool: pool.clone() }),
            None => {
                if waiting.is_some() {
                    Promise::err(::std::io::Error::new(::std::io::ErrorKind::Other,
                                                       "another client is already waiting"))
                } else {
                    let (promise, fulfiller) = Promise::and_fulfiller();
                    *waiting = Some(fulfiller);
                    promise
                }
            }
        }
    }

    pub fn push(pool: &Rc<RefCell<BufferPool>>, buf: Vec<u8>) {
        let waiting = pool.borrow_mut().waiting.take();
        match waiting {
            Some(fulfiller) => fulfiller.fulfill(Buffer { buf: buf, pool: pool.clone() }),
            None => pool.borrow_mut().buffers.push(buf),
        }
    }
}

// A buffer borrowed from a BufferPool. When a Buffer dropped, its storage is returned to the pool.
struct Buffer {
    buf: Vec<u8>,
    pool: Rc<RefCell<BufferPool>>,
}

impl Drop for Buffer {
    fn drop(&mut self) {
        let buf = ::std::mem::replace(&mut self.buf, Vec::with_capacity(0));
        BufferPool::push(&self.pool, buf);
    }
}

impl AsRef<[u8]> for Buffer {
    fn as_ref<'a>(&'a self) -> &'a [u8] { &self.buf[..] }
}

impl AsMut<[u8]> for Buffer {
    fn as_mut<'a>(&'a mut self) -> &'a mut [u8] { &mut self.buf[..] }
}

/// Reads `buf`-sized chunks of bytes from a stream until end-of-file, immediately writing each
/// chunk back to the same stream. Note that this function is recursive. In a naive implementation
/// of promises, such a function could potentially create an unbounded chain of promises. However,
/// GJ implements a tail-call optimization that shortens promise chains when possible, and therefore
/// this loop can run indefinitely, consuming only a small, bounded amount of memory.
fn echo(mut stream: gjio::SocketStream, buf: Buffer) -> Promise<(), ::std::io::Error> {
    stream.try_read(buf, 1).then(move |(buf, n)| {
        if n == 0 { // EOF
            Promise::ok(())
        } else {
            stream.write(BufferPrefix::new(buf, n)).then(move |prefix| {
                echo(stream, prefix.buf)
            })
        }
    })
}

struct Reaper;

impl TaskReaper<(), ::std::io::Error> for Reaper {
    fn task_failed(&mut self, error: ::std::io::Error) {
        println!("Task failed: {}", error);
    }
}

/// Waits for a buffer from the pool, accepts a connection, then spawns an echo() task on that
/// connection with that buffer.
fn accept_loop(listener: gjio::SocketListener,
               mut task_set: TaskSet<(), ::std::io::Error>,
               buffer_pool: Rc<RefCell<BufferPool>>)
               -> Promise<(), ::std::io::Error>
{
    BufferPool::pop(&buffer_pool).then(move |buf| {
        listener.accept().then(move |stream| {
            task_set.add(echo(stream, buf));
            accept_loop(listener, task_set, buffer_pool)
        })
    })
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 2 {
        println!("usage: {} HOST:PORT", args[0]);
        return;
    }
    let buffer_pool = Rc::new(RefCell::new(BufferPool::new(1024, 64)));

    EventLoop::top_level(move |wait_scope| -> Result<(), ::std::io::Error> {
        use std::net::ToSocketAddrs;
        let mut event_port = try!(gjio::EventPort::new());
        let network = event_port.get_network();
        let addr = try!(args[1].to_socket_addrs()).next().expect("could not parse address");
        let mut address = network.get_tcp_address(addr);
        let listener = try!(address.listen());
        let reaper = Box::new(Reaper);
        accept_loop(listener, TaskSet::new(reaper), buffer_pool).wait(wait_scope, &mut event_port)
    }).expect("top level");
}
<|endoftext|>


<commit_before>#![cfg(feature = "alloc")]

extern crate nom;
extern crate jemallocator;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

use nom::{
  branch::alt,
  bytes::complete::{escaped, tag, take_while},
  character::complete::{alphanumeric1 as alphanumeric, char, one_of},
  combinator::{map, opt, cut},
  error::{context, ErrorKind, ParseError},
  error::{VerboseError, VerboseErrorKind},
  multi::separated_list,
  number::complete::double,
  sequence::{delimited, preceded, separated_pair, terminated},
  Err, IResult, Offset,
};
use std::collections::HashMap;
use std::iter::repeat;
use std::str;

#[derive(Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  let chars = " \t\r\n";

  take_while(move |c| chars.contains(c))(i)
}

fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  escaped(alphanumeric, '\\', one_of("\"n\\"))(i)
}

fn string<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  context("string",
    preceded(
      char('\"'),
      cut(terminated(
          parse_str,
          char('\"')
  ))))(i)
}

fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
  alt((
      map(tag("false"), |_| false),
      map(tag("true"), |_| true)
  ))(input)
}

fn array<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Vec<JsonValue>, E> {
  context(
    "array",
    preceded(char('['),
    cut(terminated(
      separated_list(preceded(sp, char(',')), value),
      preceded(sp, char(']'))))
  ))(i)
}

fn key_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (&'a str, JsonValue), E> {
separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), value)(i)
}

fn hash<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, HashMap<String, JsonValue>, E> {
  context(
    "map",
    preceded(char('{'),
    cut(terminated(
      map(
        separated_list(preceded(sp, char(',')), key_value),
        |tuple_vec| {
          tuple_vec.into_iter().map(|(k, v)| (String::from(k), v)).collect()
      }),
      preceded(sp, char('}')),
    ))
  ))(i)
}

fn value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
  preceded(
    sp,
    alt((
      map(hash, JsonValue::Object),
      map(array, JsonValue::Array),
      map(string, |s| JsonValue::Str(String::from(s))),
      map(double, JsonValue::Num),
      map(boolean, JsonValue::Boolean),
    )),
  )(i)
}

fn root<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
  delimited(
    sp,
    alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
    opt(sp),
  )(i)
}

fn convert_error(input: &str, e: VerboseError<&str>) -> String {
  let lines: Vec<_> = input.lines().map(String::from).collect();

  let mut result = String::new();

  for (i, (substring, kind)) in e.errors.iter().enumerate() {
    let mut offset = input.offset(substring);

    let mut line = 0;
    let mut column = 0;

    for (j, l) in lines.iter().enumerate() {
      if offset <= l.len() {
        line = j;
        column = offset;
        break;
      } else {
        offset = offset - l.len();
      }
    }

    match kind {
      VerboseErrorKind::Char(c) => {
        result += &format!("{}: at line {}:\n", i, line);
        result += &lines[line];
        result += "\n";
        if column > 0 {
          result += &repeat(' ').take(column - 1).collect::<String>();
        }
        result += "^\n";
        result += &format!("expected '{}', found {}\n\n", c, substring.chars().next().unwrap());
      }
      VerboseErrorKind::Context(s) => {
        result += &format!("{}: at line {}, in {}:\n", i, line, s);
        result += &lines[line];
        result += "\n";
        if column > 0 {
          result += &repeat(' ').take(column - 1).collect::<String>();
        }
        result += "^\n\n";
      }
      _ => {}
    }
  }

  result
}

fn main() {
  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { 1\"hello\" : \"world\"
  }
  } ";

  println!("will try to parse:\n\n**********\n{}\n**********\n", data);
  println!(
    "basic errors - `root::<(&str, ErrorKind)>(data)`:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );
  println!("parsed verbose: {:#?}", root::<VerboseError<&str>>(data));

  match root::<VerboseError<&str>>(data) {
    Err(Err::Error(e)) | Err(Err::Failure(e)) => {
      println!("verbose errors - `root::<VerboseError>(data)`:\n{}", convert_error(data, e));
    }
    _ => panic!(),
  }
}
<commit_msg>fix column position<commit_after>#![cfg(feature = "alloc")]

extern crate nom;
extern crate jemallocator;

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

use nom::{
  branch::alt,
  bytes::complete::{escaped, tag, take_while},
  character::complete::{alphanumeric1 as alphanumeric, char, one_of},
  combinator::{map, opt, cut},
  error::{context, ErrorKind, ParseError},
  error::{VerboseError, VerboseErrorKind},
  multi::separated_list,
  number::complete::double,
  sequence::{delimited, preceded, separated_pair, terminated},
  Err, IResult, Offset,
};
use std::collections::HashMap;
use std::iter::repeat;
use std::str;

#[derive(Debug, PartialEq)]
pub enum JsonValue {
  Str(String),
  Boolean(bool),
  Num(f64),
  Array(Vec<JsonValue>),
  Object(HashMap<String, JsonValue>),
}

fn sp<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  let chars = " \t\r\n";

  take_while(move |c| chars.contains(c))(i)
}

fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  escaped(alphanumeric, '\\', one_of("\"n\\"))(i)
}

fn string<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
  context("string",
    preceded(
      char('\"'),
      cut(terminated(
          parse_str,
          char('\"')
  ))))(i)
}

fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
  alt((
      map(tag("false"), |_| false),
      map(tag("true"), |_| true)
  ))(input)
}

fn array<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Vec<JsonValue>, E> {
  context(
    "array",
    preceded(char('['),
    cut(terminated(
      separated_list(preceded(sp, char(',')), value),
      preceded(sp, char(']'))))
  ))(i)
}

fn key_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (&'a str, JsonValue), E> {
separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), value)(i)
}

fn hash<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, HashMap<String, JsonValue>, E> {
  context(
    "map",
    preceded(char('{'),
    cut(terminated(
      map(
        separated_list(preceded(sp, char(',')), key_value),
        |tuple_vec| {
          tuple_vec.into_iter().map(|(k, v)| (String::from(k), v)).collect()
      }),
      preceded(sp, char('}')),
    ))
  ))(i)
}

fn value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
  preceded(
    sp,
    alt((
      map(hash, JsonValue::Object),
      map(array, JsonValue::Array),
      map(string, |s| JsonValue::Str(String::from(s))),
      map(double, JsonValue::Num),
      map(boolean, JsonValue::Boolean),
    )),
  )(i)
}

fn root<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
  delimited(
    sp,
    alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
    opt(sp),
  )(i)
}

fn convert_error(input: &str, e: VerboseError<&str>) -> String {
  let lines: Vec<_> = input.lines().map(String::from).collect();

  let mut result = String::new();

  for (i, (substring, kind)) in e.errors.iter().enumerate() {
    let mut offset = input.offset(substring);

    let mut line = 0;
    let mut column = 0;

    for (j, l) in lines.iter().enumerate() {
      if offset <= l.len() {
        line = j;
        column = offset;
        break;
      } else {
        offset = offset - l.len() - 1;
      }

    }

    match kind {
      VerboseErrorKind::Char(c) => {
        result += &format!("{}: at line {}:\n", i, line);
        result += &lines[line];
        result += "\n";

        if column > 0 {
          result += &repeat(' ').take(column).collect::<String>();
        }
        result += "^\n";
        result += &format!("expected '{}', found {}\n\n", c, substring.chars().next().unwrap());
      }
      VerboseErrorKind::Context(s) => {
        result += &format!("{}: at line {}, in {}:\n", i, line, s);
        result += &lines[line];
        result += "\n";
        if column > 0 {
          result += &repeat(' ').take(column).collect::<String>();
        }
        result += "^\n\n";
      },
      /*VerboseErrorKind::Nom(e) => {
        result += &format!("{}: at line {}, in {:?}:\n", i, line, e);
        result += &lines[line];
        result += "\n";
        if column > 0 {
          result += &repeat(' ').take(column).collect::<String>();
        }
        result += "^\n\n";
      }*/
      _ => {}
    }
  }

  result
}

fn main() {
  let data = "  { \"a\"\t: 42,
  \"b\": [ \"x\", \"y\", 12 ] ,
  \"c\": { 1\"hello\" : \"world\"
  }
  } ";

  println!("will try to parse:\n\n**********\n{}\n**********\n", data);
  println!(
    "basic errors - `root::<(&str, ErrorKind)>(data)`:\n{:#?}\n",
    root::<(&str, ErrorKind)>(data)
  );
  println!("parsed verbose: {:#?}", root::<VerboseError<&str>>(data));

  match root::<VerboseError<&str>>(data) {
    Err(Err::Error(e)) | Err(Err::Failure(e)) => {
      println!("verbose errors - `root::<VerboseError>(data)`:\n{}", convert_error(data, e));
    }
    _ => panic!(),
  }
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::geom::point::Point;
use polydraw::draw::RGB;

struct Poly {
   points: Vec<Point>,
   color: RGB,
}

impl Poly {
   fn min_max_y_index(&self) -> (usize, usize) {
      let (first, rest) = self.points.split_first().unwrap();

      let mut min_y = first.y;
      let mut max_y = min_y;
      let mut min_index: usize = 0;
      let mut max_index: usize = 0;

      for (index, point) in rest.iter().enumerate() {
         if point.y < min_y {
            min_index = index + 1;
            min_y = point.y;
         } else if point.y > max_y {
            max_index = index + 1;
            max_y = point.y;
         }
      }

      (min_index, max_index)
   }
}

struct Scene {
   polys: Vec<Poly>,
}

impl Scene {
   #[inline]
   fn new() -> Self {
      Scene {
         polys: Vec::new(),
      }
   }

   #[inline]
   pub fn push(&mut self, poly: Poly) {
      self.polys.push(poly);
   }
}

struct DevRenderer {
   scene: Scene,
}

impl DevRenderer {
   fn new(scene: Scene) -> Self {
      DevRenderer {
         scene: scene,
      }
   }

   fn _render_poly(&self, frame: &mut Frame, poly: &Poly) {
      let (min_y_index, max_y_index) = poly.min_max_y_index();

      println!("MIN [{:?}] = {:?}", min_y_index, poly.points[min_y_index]);

      println!("MAX [{:?}] = {:?}", max_y_index, poly.points[max_y_index]);

      for point in poly.points.iter() {
         frame.put_pixel(point.x as i32, point.y as i32, &poly.color)
      }
   }
}

impl Renderer for DevRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      for poly in self.scene.polys.iter() {
         self._render_poly(frame, poly);
      }

      panic!("Bye!");
   }
}

fn main() {
   let mut scene = Scene::new();

   let poly_a = Poly {
      points: vec![
         Point::new(1100, 400),
         Point::new(500, 700),
         Point::new(200, 200),
      ],
      color: RGB::new(34, 78, 29),
   };

   let poly_b = Poly {
      points: vec![
         Point::new(100, 500),
         Point::new(700, 100),
         Point::new(900, 200),
         Point::new(900, 1000),
      ],
      color: RGB::new(128, 59, 89),
   };

   scene.push(poly_a);
   scene.push(poly_b);

   let mut renderer = DevRenderer::new(scene);

   Application::new()
      .renderer(&mut renderer)
      .title("Dev Rasterizer")
      .size(800, 450)
      .run();
}

<commit_msg>Iterating the points spanning from min y to max y<commit_after>extern crate polydraw;

use polydraw::{Application, Renderer, Frame};
use polydraw::geom::point::Point;
use polydraw::draw::RGB;

struct Poly {
   points: Vec<Point>,
   color: RGB,
}

impl Poly {
   fn min_max_y_index(&self) -> (usize, usize) {
      let (first, rest) = self.points.split_first().unwrap();

      let mut min_y = first.y;
      let mut max_y = min_y;
      let mut min_index: usize = 0;
      let mut max_index: usize = 0;

      for (index, point) in rest.iter().enumerate() {
         if point.y < min_y {
            min_index = index + 1;
            min_y = point.y;
         } else if point.y > max_y {
            max_index = index + 1;
            max_y = point.y;
         }
      }

      (min_index, max_index)
   }
}

struct Scene {
   polys: Vec<Poly>,
}

impl Scene {
   #[inline]
   fn new() -> Self {
      Scene {
         polys: Vec::new(),
      }
   }

   #[inline]
   pub fn push(&mut self, poly: Poly) {
      self.polys.push(poly);
   }
}

struct DevRenderer {
   scene: Scene,
}

impl DevRenderer {
   fn new(scene: Scene) -> Self {
      DevRenderer {
         scene: scene,
      }
   }

   fn _render_poly(&self, frame: &mut Frame, poly: &Poly) {
      let (min_y_index, max_y_index) = poly.min_max_y_index();

      println!("MIN [{:?}] = {:?}", min_y_index, poly.points[min_y_index]);

      println!("MAX [{:?}] = {:?}", max_y_index, poly.points[max_y_index]);

      let points_len = poly.points.len();
      let count = if max_y_index > min_y_index {
         max_y_index - min_y_index
      } else {
         points_len - max_y_index + min_y_index - 1
      };

      println!("COUNT = {}", count);

      let mut index = min_y_index;
      for _ in 0..count {
         if index >= points_len {
            index -= points_len;
         }

         println!("[{}] = {:?}", index, poly.points[index]);

         index += 1;
      }

      for point in poly.points.iter() {
         frame.put_pixel(point.x as i32, point.y as i32, &poly.color)
      }
   }
}

impl Renderer for DevRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      for poly in self.scene.polys.iter() {
         self._render_poly(frame, poly);
      }

      panic!("Bye!");
   }
}

fn main() {
   let mut scene = Scene::new();

   let poly_a = Poly {
      points: vec![
         Point::new(1100, 400),
         Point::new(500, 700),
         Point::new(200, 200),
      ],
      color: RGB::new(34, 78, 29),
   };

   let poly_b = Poly {
      points: vec![
         Point::new(100, 500),
         Point::new(700, 100),
         Point::new(900, 200),
         Point::new(900, 1000),
      ],
      color: RGB::new(128, 59, 89),
   };

   scene.push(poly_a);
   scene.push(poly_b);

   let mut renderer = DevRenderer::new(scene);

   Application::new()
      .renderer(&mut renderer)
      .title("Dev Rasterizer")
      .size(800, 450)
      .run();
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate dimensioned;
// use dimensioned::{Dim, Wrap, Dimension};
use dimensioned::dimensioned::*;
//use dimensioned::*;
use dimensioned::u::*;
use std::ops::*;
use std::fmt;
use std::num::Float;
//use peano::*;

pub struct Vector2d {
    pub x: f64,
    pub y: f64,
}

impl Vector2d {
    fn norm(self) -> f64 { self.norm2().sqrt() }
    fn norm2(self) -> f64 { self.dot(self) }
    fn normalize(self) -> Vector2d { self / self.norm() }
    fn cross(self, rhs: Vector2d) -> f64 { self.x*rhs.y - self.y*rhs.x }
    fn dot(self, rhs: Vector2d) -> f64 { self.x*rhs.x + self.y*rhs.y }
}

trait VectorNorm {
    type Output;
    fn norm(self) -> <Self as VectorNorm>::Output;
}

impl<T: Dimension> VectorNorm for Dim<T, Vector2d> {
    type Output = Dim<T, f64>;
    fn norm(self) -> Dim<T, f64> { self.wrap( Vector2d::norm(self.0) ) }
}

macro_rules! wrap_member {
    ($Trait:ident, $DimOp:ident, $Self:ident, $Out:ident, $fun:ident(self, $($arg:ident),*) ) => (
        pub trait $Trait {
            type Output;
            fn $fun(self $(, $arg)*) -> <Self as $Trait>::Output;
        }
        impl<T: Dimension> $Trait for Dim<T, $Self> {
            type Output = Dim<>
        }
        )
}

// dim_unary!(VectorNorm, KeepDim, norm);
//wrap_binary!(Trait, DimOp, Self, Output, flist)

// macro_rules! wrap_binary {
//     ($Trait:ident, $DimOp:ident, $Self:ident, $Out:ident, $($fun:ident),*) => (
//         pub trait $Trait<RHS = Self> {
//             type Output;
//             $(fn $fun(self, rhs: RHS) -> <Self as $Trait<RHS>>::Output;)*
//         }
//         impl<RHS> $Trait<RHS> for $Self {
//             type Output = <$Self as $Trait<RHS>>::Output;
//             $(fn $fun(self, rhs: RHS) -> <Self as $Trait<RHS>>::Output { self.fun(rhs) } )*
//         }
//         dim_binary!($Trait, $DimOp $(, $fun)*);
//         )
// }

// macro_rules! wrapper {
// pub trait $
//     fn $fun -> $Output;
// }
//wrap_binary!(VectorProd, AddDim, Vector2d, f64, dot, cross);
// dim_binary!(VectorProd, AddDim, cross, dot);

// macro_rules! dim_unary {
//     ($Trait: ident, $op: ident, $($fun: ident),*) => (
//         impl<T, V> $Trait for Dim<T, V>
//             where T: $op<T>, V: $Trait, <T as $op<T>>::Output: Dimension {
//                 type Output = Dim<<T as $op<T>>::Output, <V as $Trait>::Output>;
//                 $(fn $fun(self) -> Dim<<T as $op<T>>::Output, <V as $Trait>::Output> {
//                     Dim( (self.0).$fun() )
//                 })*
//             }
//         )
// }

impl Copy for Vector2d {}
impl Add for Vector2d {
    type Output = Vector2d;
    fn add(self, v: Vector2d) -> Vector2d { Vector2d{x: self.x + v.x, y: self.y + v.y} }
}
impl Sub for Vector2d {
    type Output = Vector2d;
    fn sub(self, v: Vector2d) -> Vector2d { Vector2d{x: self.x - v.x, y: self.y - v.y} }
}
impl Neg for Vector2d {
    type Output = Vector2d;
    fn neg(self) -> Vector2d { Vector2d{x: -self.x, y: -self.y} }
}

impl Mul<f64> for Vector2d {
    type Output = Vector2d;
    fn mul(self, rhs: f64) -> Vector2d {
        Vector2d{x: rhs*self.x, y: rhs*self.y}
    }
}

impl Div<f64> for Vector2d {
    type Output = Vector2d;
    fn div(self, scalar: f64) -> Vector2d { Vector2d{x: self.x/scalar, y: self.y/scalar} }
}
impl fmt::Display for Vector2d {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) }
}

fn main() {
    let xhat: Dim<Unitless, Vector2d> = Dim(Vector2d{x: 1.0, y: 0.0});
    let yhat: Dim<Unitless, Vector2d> = Dim(Vector2d{x: 0.0, y: 1.0});
    let v = Vector2d{x: 1.1, y: 1.1};
    v.norm();

    let x = unit;

    println!("x: {}", x );
    // println!("square? {}", x.pow2() );

    xhat.norm();
}
<commit_msg>Update for new nightly<commit_after>#[macro_use]
extern crate dimensioned;
// use dimensioned::{Dim, Wrap, Dimension};
use dimensioned::dimensioned::*;
//use dimensioned::*;
use dimensioned::u::*;
use std::ops::*;
use std::fmt;
use std::num::Float;
//use peano::*;

pub struct Vector2d {
    pub x: f64,
    pub y: f64,
}

impl Vector2d {
    fn norm(self) -> f64 { self.norm2().sqrt() }
    fn norm2(self) -> f64 { self.dot(self) }
    fn normalize(self) -> Vector2d { self / self.norm() }
    fn cross(self, rhs: Vector2d) -> f64 { self.x*rhs.y - self.y*rhs.x }
    fn dot(self, rhs: Vector2d) -> f64 { self.x*rhs.x + self.y*rhs.y }
}

trait VectorNorm {
    type Output;
    fn norm(self) -> <Self as VectorNorm>::Output;
}

impl<T: Dimension> VectorNorm for Dim<T, Vector2d> {
    type Output = Dim<T, f64>;
    fn norm(self) -> Dim<T, f64> { self.wrap( Vector2d::norm(self.0) ) }
}

macro_rules! wrap_member {
    ($Trait:ident, $DimOp:ident, $V:ident, $Out:ident, $fun:ident(self, $($arg:ident),*) ) => (
        pub trait $Trait {
            type Output;
            fn $fun(self $(, $arg)*) -> <Self as $Trait>::Output;
        }
        impl<T: Dimension> $Trait for Dim<T, $V> {
            type Output = Dim<>
        }
        )
}

// dim_unary!(VectorNorm, KeepDim, norm);
//wrap_binary!(Trait, DimOp, Self, Output, flist)

// macro_rules! wrap_binary {
//     ($Trait:ident, $DimOp:ident, $V:ident, $Out:ident, $($fun:ident),*) => (
//         pub trait $Trait<RHS = Self> {
//             type Output;
//             $(fn $fun(self, rhs: RHS) -> <Self as $Trait<RHS>>::Output;)*
//         }
//         impl<RHS> $Trait<RHS> for $V {
//             type Output = <$V as $Trait<RHS>>::Output;
//             $(fn $fun(self, rhs: RHS) -> <Self as $Trait<RHS>>::Output { self.fun(rhs) } )*
//         }
//         dim_binary!($Trait, $DimOp $(, $fun)*);
//         )
// }

// macro_rules! wrapper {
// pub trait $
//     fn $fun -> $Output;
// }
//wrap_binary!(VectorProd, AddDim, Vector2d, f64, dot, cross);
// dim_binary!(VectorProd, AddDim, cross, dot);

// macro_rules! dim_unary {
//     ($Trait: ident, $op: ident, $($fun: ident),*) => (
//         impl<T, V> $Trait for Dim<T, V>
//             where T: $op<T>, V: $Trait, <T as $op<T>>::Output: Dimension {
//                 type Output = Dim<<T as $op<T>>::Output, <V as $Trait>::Output>;
//                 $(fn $fun(self) -> Dim<<T as $op<T>>::Output, <V as $Trait>::Output> {
//                     Dim( (self.0).$fun() )
//                 })*
//             }
//         )
// }

impl Copy for Vector2d {}
impl Add for Vector2d {
    type Output = Vector2d;
    fn add(self, v: Vector2d) -> Vector2d { Vector2d{x: self.x + v.x, y: self.y + v.y} }
}
impl Sub for Vector2d {
    type Output = Vector2d;
    fn sub(self, v: Vector2d) -> Vector2d { Vector2d{x: self.x - v.x, y: self.y - v.y} }
}
impl Neg for Vector2d {
    type Output = Vector2d;
    fn neg(self) -> Vector2d { Vector2d{x: -self.x, y: -self.y} }
}

impl Mul<f64> for Vector2d {
    type Output = Vector2d;
    fn mul(self, rhs: f64) -> Vector2d {
        Vector2d{x: rhs*self.x, y: rhs*self.y}
    }
}

impl Div<f64> for Vector2d {
    type Output = Vector2d;
    fn div(self, scalar: f64) -> Vector2d { Vector2d{x: self.x/scalar, y: self.y/scalar} }
}
impl fmt::Display for Vector2d {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) }
}

fn main() {
    let xhat: Dim<Unitless, Vector2d> = Dim(Vector2d{x: 1.0, y: 0.0});
    let yhat: Dim<Unitless, Vector2d> = Dim(Vector2d{x: 0.0, y: 1.0});
    let v = Vector2d{x: 1.1, y: 1.1};
    v.norm();

    let x = unit;

    println!("x: {}", x );
    // println!("square? {}", x.pow2() );

    xhat.norm();
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, ReconfigurationParams, RecoveryTimeParams,
        StateSyncPerformanceParams, TwinValidatorsParams, ValidatorVersioningParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::non_zero_gas_price(0, 1)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        // This can't be run before any experiment that requires clean_data.
        experiments.push(Box::new(
            ReconfigurationParams {
                count: 101,
                emit_txn: false,
            }
            .build(cluster),
        ));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    fn new_versioning_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            ValidatorVersioningParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        Ok(Self { experiments })
    }

    fn new_invalid_tx_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::mix_invalid_tx(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_state_sync_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(StateSyncPerformanceParams::new(60).build(cluster)));
        Self { experiments }
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            "versioning" => Self::new_versioning_suite(cluster),
            "invalid" => Ok(Self::new_invalid_tx_suite(cluster)),
            "state_sync" => Ok(Self::new_state_sync_suite(cluster)),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<commit_msg>[Cluster Test] Add state sync performance test to new_pre_release suite<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, ReconfigurationParams, RecoveryTimeParams,
        StateSyncPerformanceParams, TwinValidatorsParams, ValidatorVersioningParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::non_zero_gas_price(0, 1)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(StateSyncPerformanceParams::new(60).build(cluster)));
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        // This can't be run before any experiment that requires clean_data.
        experiments.push(Box::new(
            ReconfigurationParams {
                count: 101,
                emit_txn: false,
            }
            .build(cluster),
        ));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    fn new_versioning_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            ValidatorVersioningParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        Ok(Self { experiments })
    }

    fn new_invalid_tx_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::mix_invalid_tx(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_state_sync_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(StateSyncPerformanceParams::new(60).build(cluster)));
        Self { experiments }
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            "versioning" => Self::new_versioning_suite(cluster),
            "invalid" => Ok(Self::new_invalid_tx_suite(cluster)),
            "state_sync" => Ok(Self::new_state_sync_suite(cluster)),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;

use ply_rs::ply;
use ply_rs::parser;

use {Normal3f, Point2f, Point3f};
use paramset::ParamSet;
use shapes::Shape;
use shapes::mesh::create_triangle_mesh;
use texture::Texture;
use transform::Transform;

pub fn create(o2w: &Transform,
              _w2o: &Transform,
              reverse_orientation: bool,
              params: &mut ParamSet,
              _float_textures: &HashMap<String, Arc<Texture<f32>>>)
              -> Vec<Arc<Shape>> {
    let filename = params.find_one_filename("filename", "".into());
    let f = File::open(&filename).unwrap();
    let mut f = BufReader::new(f);

    // create a parser
    let vertex_parser = parser::Parser::<Vertex>::new();
    let face_parser = parser::Parser::<Face>::new();

    // use the parser: read the entire file
    let header = vertex_parser.read_header(&mut f).unwrap();
    let mut vertex_count = 0;
    let mut face_count = 0;
    let mut has_normals = false;
    let mut has_texture = false;
    for (key, elem) in &header.elements {
        if key == "vertex" {
            vertex_count = elem.count;
            if !elem.properties.contains_key("x") || !elem.properties.contains_key("y") ||
               !elem.properties.contains_key("z") {
                error!("PLY file \"{}\": Vertex coordinate property not found",
                       filename);
                return Vec::new();
            }
            if elem.properties.contains_key("nx") && elem.properties.contains_key("ny") &&
               elem.properties.contains_key("nz") {
                has_normals = true;
            }
            if (elem.properties.contains_key("u") && elem.properties.contains_key("v")) ||
               (elem.properties.contains_key("s") && elem.properties.contains_key("t")) ||
               (elem.properties.contains_key("texture_u") &&
                elem.properties.contains_key("texture_v")) ||
               (elem.properties.contains_key("texture_s") &&
                elem.properties.contains_key("texture_t")) {
                has_texture = true;
            }
        } else if key == "face" {
            face_count = elem.count;
        }
    }

    if vertex_count == 0 || face_count == 0 {
        error!("PLY file \"{}\" is invalid! No face/vertex elements found!",
               filename);
        return Vec::new();
    } else {
        info!("Loading PLY file with {} vertices and {} faces",
              vertex_count,
              face_count);
    }

    let mut vertices = Vec::new();
    let mut faces = Vec::new();
    for (_key, elem) in &header.elements {
        match elem.name.as_ref() {
            "vertex" => {
                vertices = vertex_parser
                    .read_payload_for_element(&mut f, elem, &header)
                    .unwrap();
                // TODO normals + texture
            }
            "face" => {
                faces = face_parser
                    .read_payload_for_element(&mut f, elem, &header)
                    .unwrap();
            }
            _ => panic!("Unexpected element \"{}\"", elem.name),
        }
    }

    let vertex_indices: Vec<usize> = faces.into_iter().flat_map(|f| {
        let length = f.vertex_indices.len();
        if length != 3 && length != 4 {
            warn!("plymesh: Ignoring face with {} vertices (only triangles and quads are supported!", f.vertex_indices.len());
            Vec::new()
        } else {
            let mut vec = Vec::new();
            vec.push(f.vertex_indices[0] as usize);
            vec.push(f.vertex_indices[1] as usize);
            vec.push(f.vertex_indices[2] as usize);
            if length == 4 {
                // If it's a quad, split it into 2 triangles
                vec.push(f.vertex_indices[3] as usize);
                vec.push(f.vertex_indices[0] as usize);
                vec.push(f.vertex_indices[2] as usize);
            }

            vec
        }
    }).collect();

    let mut p = Vec::with_capacity(vertex_count);
    let mut n = Vec::with_capacity(vertex_count);
    let mut uv = Vec::with_capacity(vertex_count);

    for v in vertices {
        p.push(v.p);
        if has_normals {
            n.push(v.n);
        }
        if has_texture {
            uv.push(v.uv);
        }
    }

    create_triangle_mesh(o2w,
                         reverse_orientation,
                         &vertex_indices,
                         &p,
                         None,
                         if has_normals { Some(&n) } else { None },
                         if has_texture { Some(&uv) } else { None })
}

struct Vertex {
    p: Point3f,
    n: Normal3f,
    uv: Point2f,
}

impl ply::PropertyAccess for Vertex {
    fn new() -> Vertex {
        Vertex {
            p: Point3f::default(),
            n: Normal3f::default(),
            uv: Point2f::default(),
        }
    }

    fn set_property(&mut self, key: String, prop: ply::Property) {
        match (key.as_ref(), prop) {
            // point
            ("x", ply::Property::Float(v)) => self.p.x = v,
            ("y", ply::Property::Float(v)) => self.p.y = v,
            ("z", ply::Property::Float(v)) => self.p.z = v,
            // normal
            ("nx", ply::Property::Float(v)) => self.n.x = v,
            ("ny", ply::Property::Float(v)) => self.n.y = v,
            ("nz", ply::Property::Float(v)) => self.n.z = v,
            // texture coordinates
            ("u", ply::Property::Float(v)) |
            ("texture_u", ply::Property::Float(v)) |
            ("s", ply::Property::Float(v)) |
            ("texture_s", ply::Property::Float(v)) => self.uv.x = v,
            ("v", ply::Property::Float(v)) |
            ("t", ply::Property::Float(v)) |
            ("texture_v", ply::Property::Float(v)) |
            ("texture_t", ply::Property::Float(v)) => self.uv.y = v,
            _ => panic!("Unknown property \"{}\" found for vertex element", key),
        }
    }
}

struct Face {
    vertex_indices: Vec<i32>,
}

impl ply::PropertyAccess for Face {
    fn new() -> Face {
        Face { vertex_indices: Vec::new() }
    }

    fn set_property(&mut self, key: String, prop: ply::Property) {
        match (key.as_ref(), prop) {
            ("vertex_indices", ply::Property::ListInt(v)) => self.vertex_indices = v,
            (_k, _) => panic!("Face: Invalid combination key/value for key {}", key),
        }
    }
}
<commit_msg>Don't panic if we find unknown properties in a PLY file<commit_after>use std::sync::Arc;
use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;

use ply_rs::ply;
use ply_rs::parser;

use {Normal3f, Point2f, Point3f};
use paramset::ParamSet;
use shapes::Shape;
use shapes::mesh::create_triangle_mesh;
use texture::Texture;
use transform::Transform;

pub fn create(o2w: &Transform,
              _w2o: &Transform,
              reverse_orientation: bool,
              params: &mut ParamSet,
              _float_textures: &HashMap<String, Arc<Texture<f32>>>)
              -> Vec<Arc<Shape>> {
    let filename = params.find_one_filename("filename", "".into());
    let f = File::open(&filename).unwrap();
    let mut f = BufReader::new(f);

    // create a parser
    let vertex_parser = parser::Parser::<Vertex>::new();
    let face_parser = parser::Parser::<Face>::new();

    // use the parser: read the entire file
    let header = vertex_parser.read_header(&mut f).unwrap();
    let mut vertex_count = 0;
    let mut face_count = 0;
    let mut has_normals = false;
    let mut has_texture = false;
    for (key, elem) in &header.elements {
        if key == "vertex" {
            vertex_count = elem.count;
            if !elem.properties.contains_key("x") || !elem.properties.contains_key("y") ||
               !elem.properties.contains_key("z") {
                error!("PLY file \"{}\": Vertex coordinate property not found",
                       filename);
                return Vec::new();
            }
            if elem.properties.contains_key("nx") && elem.properties.contains_key("ny") &&
               elem.properties.contains_key("nz") {
                has_normals = true;
            }
            if (elem.properties.contains_key("u") && elem.properties.contains_key("v")) ||
               (elem.properties.contains_key("s") && elem.properties.contains_key("t")) ||
               (elem.properties.contains_key("texture_u") &&
                elem.properties.contains_key("texture_v")) ||
               (elem.properties.contains_key("texture_s") &&
                elem.properties.contains_key("texture_t")) {
                has_texture = true;
            }
        } else if key == "face" {
            face_count = elem.count;
        }
    }

    if vertex_count == 0 || face_count == 0 {
        error!("PLY file \"{}\" is invalid! No face/vertex elements found!",
               filename);
        return Vec::new();
    } else {
        info!("Loading PLY file with {} vertices and {} faces",
              vertex_count,
              face_count);
    }

    let mut vertices = Vec::new();
    let mut faces = Vec::new();
    for (_key, elem) in &header.elements {
        match elem.name.as_ref() {
            "vertex" => {
                vertices = vertex_parser
                    .read_payload_for_element(&mut f, elem, &header)
                    .unwrap();
                // TODO normals + texture
            }
            "face" => {
                faces = face_parser
                    .read_payload_for_element(&mut f, elem, &header)
                    .unwrap();
            }
            _ => panic!("Unexpected element \"{}\"", elem.name),
        }
    }

    let vertex_indices: Vec<usize> = faces.into_iter().flat_map(|f| {
        let length = f.vertex_indices.len();
        if length != 3 && length != 4 {
            warn!("plymesh: Ignoring face with {} vertices (only triangles and quads are supported!", f.vertex_indices.len());
            Vec::new()
        } else {
            let mut vec = Vec::new();
            vec.push(f.vertex_indices[0] as usize);
            vec.push(f.vertex_indices[1] as usize);
            vec.push(f.vertex_indices[2] as usize);
            if length == 4 {
                // If it's a quad, split it into 2 triangles
                vec.push(f.vertex_indices[3] as usize);
                vec.push(f.vertex_indices[0] as usize);
                vec.push(f.vertex_indices[2] as usize);
            }

            vec
        }
    }).collect();

    let mut p = Vec::with_capacity(vertex_count);
    let mut n = Vec::with_capacity(vertex_count);
    let mut uv = Vec::with_capacity(vertex_count);

    for v in vertices {
        p.push(v.p);
        if has_normals {
            n.push(v.n);
        }
        if has_texture {
            uv.push(v.uv);
        }
    }

    create_triangle_mesh(o2w,
                         reverse_orientation,
                         &vertex_indices,
                         &p,
                         None,
                         if has_normals { Some(&n) } else { None },
                         if has_texture { Some(&uv) } else { None })
}

struct Vertex {
    p: Point3f,
    n: Normal3f,
    uv: Point2f,
}

impl ply::PropertyAccess for Vertex {
    fn new() -> Vertex {
        Vertex {
            p: Point3f::default(),
            n: Normal3f::default(),
            uv: Point2f::default(),
        }
    }

    fn set_property(&mut self, key: String, prop: ply::Property) {
        match (key.as_ref(), prop) {
            // point
            ("x", ply::Property::Float(v)) => self.p.x = v,
            ("y", ply::Property::Float(v)) => self.p.y = v,
            ("z", ply::Property::Float(v)) => self.p.z = v,
            // normal
            ("nx", ply::Property::Float(v)) => self.n.x = v,
            ("ny", ply::Property::Float(v)) => self.n.y = v,
            ("nz", ply::Property::Float(v)) => self.n.z = v,
            // texture coordinates
            ("u", ply::Property::Float(v)) |
            ("texture_u", ply::Property::Float(v)) |
            ("s", ply::Property::Float(v)) |
            ("texture_s", ply::Property::Float(v)) => self.uv.x = v,
            ("v", ply::Property::Float(v)) |
            ("t", ply::Property::Float(v)) |
            ("texture_v", ply::Property::Float(v)) |
            ("texture_t", ply::Property::Float(v)) => self.uv.y = v,
            _ => debug!("Unknown property \"{}\" found for vertex element", key),
        }
    }
}

struct Face {
    vertex_indices: Vec<i32>,
}

impl ply::PropertyAccess for Face {
    fn new() -> Face {
        Face { vertex_indices: Vec::new() }
    }

    fn set_property(&mut self, key: String, prop: ply::Property) {
        match (key.as_ref(), prop) {
            ("vertex_indices", ply::Property::ListInt(v)) => self.vertex_indices = v,
            (_k, p) => debug!("Face: Invalid combination key/value for key {} / prop {:?}", key, p),
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate rand;

use std::env;
use std::ffi::CString;
use std::fs;
use std::path::Path;
use libc::{chmod, chown, geteuid, setgid, setuid};
use rand::random;

const BASE_RUN_DIR: &'static str = "/var/tmp/progcon";
const MIN_UID: u32 = 20000;

fn main() {
    // sanity check
    let uid = unsafe { geteuid() };
    if uid != 0 {
        panic!("must be run root (setuid root)");
    }

    let base = Path::new(BASE_RUN_DIR);

    // make sure our working dir is there
    fs::create_dir_all(base).unwrap();

    // sticky allows users to delete their own directories and clean up after themselves,
    // but not other users' files. this is similar to how /tmp works.
    unsafe {
        let base_ptr = CString::new(BASE_RUN_DIR).unwrap().as_ptr();
        chmod(base_ptr, 0o1777);
    }

    // pick a random uid
    let mut uid;
    let mut working;
    loop {
        uid = MIN_UID + random::<u16>() as u32;
        println!("chose {}", uid);

        // check if that directory already exists; if it does then it's likely
        // in use by another runner.
        working = base.join(uid.to_string());
        if !working.exists() {
            break;
        }
    }

    // give it a working dir
    fs::create_dir(&working).unwrap();
    unsafe {
        let working_ptr = CString::new(working.to_str().unwrap()).unwrap().as_ptr();
        chown(working_ptr, uid, uid);
    }

    // time to drop to our user
    // XXX don't panic, need to clean up afterwards
    unsafe {
        if setgid(uid) != 0 {
            panic!("couldn't setgid");
        }
        if setuid(uid) != 0 {
            panic!("couldn't setuid");
        }
    }

    // chdir to it
    env::set_current_dir(&working);

    let newuid = unsafe { geteuid() };
    println!("i'm now {}", newuid);

    // TODO: run the thing

    fs::remove_dir_all(&working).unwrap();
}
<commit_msg>More contest-exec implementation.<commit_after>extern crate libc;
extern crate rand;

mod util;

use std::env;
use std::error::Error;
use std::fs;
use std::fs::File;
use std::io;
use std::os::unix::fs::MetadataExt;
use std::path::Path;
use std::process::{Command, exit};
use libc::{chmod, chown, geteuid, setgid, setuid};
use rand::random;
use util::{Lock, OwnedDir, own_path};

const PREFIX: &'static str = "/var/tmp/progcon-";
const LOCK_PREFIX: &'static str = "/var/tmp/progconuser-";
const MIN_UID: u32 = 20000;

fn main() {
    // find out what we're working with
    let mut args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        println!("usage: contest-exec {}workingdir command", PREFIX);
        exit(1);
    }
    let workdir = args[1].clone();
    let command = args[2].clone();
    let args = args.split_off(3);

    // be safe!
    sanity_check(&workdir);

    // pick a random uid; "reserve" it with a lock file
    let lock = pick_uid().unwrap();

    // wrapping up errors; save them for later (cleanup) instead of panicing
    su_exec(Path::new(&workdir), lock.uid, command, &args).unwrap();
}

fn sanity_check(workdir: &str) {
    // gotta be root
    let uid = unsafe { geteuid() };
    if uid != 0 {
        panic!("must be run root (setuid root)");
    }

    // ensure dir matches prefix
    if !workdir.starts_with(PREFIX) {
        panic!("given workdir doesn't start with {} ({})", PREFIX, workdir);
    }

    // ensure dir exists
    if !Path::new(workdir).exists() {
        panic!("workdir {} doesn't exist", workdir);
    }
}

fn pick_uid() -> Result<Lock, Box<Error>> {
    let mut uid;
    let mut name;
    loop {
        uid = MIN_UID + random::<u16>() as u32;
        name = format!("{}{}.lock", LOCK_PREFIX, uid);
        let path = Path::new(&name);

        if !path.exists() {
            break;
        }

        // if the lock file isn't actually owned by the user we expect,
        // then something isn't right -- remove the lock and claim it anyway.
        let metadata = try!(path.metadata());
        let lock_uid = metadata.uid();
        if lock_uid != uid {
            break;
        }
    }

    let path = Path::new(&name);
    Lock::new(path, uid)
}

fn su_exec(workdir: &Path, uid: u32, command: String, args: &Vec<String>) -> Result<(), String> {
    // claim our working directory
    // Drop will delete the directory
    let owned = OwnedDir::new(workdir, uid);

    // time to drop to our user
    unsafe {
        if setgid(uid) != 0 {
            return Err("couldn't setgid".to_string());
        }
        if setuid(uid) != 0 {
            return Err("couldn't setuid".to_string());
        }
    }

    // chdir to it
    try!(env::set_current_dir(&workdir).map_err(|e| e.to_string()));

    // run it!
    let mut run = try!(Command::new(command).args(args).spawn().map_err(|e| e.to_string()));
    try!(run.wait().map_err(|e| e.to_string()));

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::min;

use crypto::{Hash, PublicKey, HASH_SIZE};
use super::super::StorageKey;

pub const BRANCH_KEY_PREFIX: u8 = 00;
pub const LEAF_KEY_PREFIX: u8 = 01;

/// Size in bytes of the `ProofMapKey`.
pub const KEY_SIZE: usize = HASH_SIZE;
pub const DB_KEY_SIZE: usize = KEY_SIZE + 2;

/// A trait that defines a subset of storage key types which are suitable for use with
/// `ProofMapIndex`.
///
/// The size of the keys must be exactly 32 bytes and the keys must have a uniform distribution.
pub trait ProofMapKey: StorageKey {}

impl ProofMapKey for Hash {}
impl ProofMapKey for PublicKey {}
impl ProofMapKey for [u8; KEY_SIZE] {}

impl StorageKey for [u8; KEY_SIZE] {
    fn size(&self) -> usize {
        KEY_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        let mut value = [0; KEY_SIZE];
        value.copy_from_slice(buffer);
        value
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ChildKind {
    Left,
    Right,
}

/// A struct that represents a bit slices of the proof map keys.
#[derive(Clone)]
pub struct DBKey {
    data: [u8; KEY_SIZE],
    from: u16,
    to: u16,
}

impl ::std::ops::Not for ChildKind {
    type Output = ChildKind;

    fn not(self) -> ChildKind {
        match self {
            ChildKind::Left => ChildKind::Right,
            ChildKind::Right => ChildKind::Left,
        }
    }
}

impl DBKey {
    /// Create a new bit slice from the given binary data.
    pub fn leaf<K: ProofMapKey>(key: &K) -> DBKey {
        debug_assert_eq!(key.size(), KEY_SIZE);

        let mut data = [0; KEY_SIZE];
        key.write(&mut data);
        DBKey {
            data: data,
            from: 0,
            to: (KEY_SIZE * 8) as u16,
        }
    }

    #[doc(hidden)]
    pub fn from(&self) -> u16 {
        self.from
    }

    // TODO: terrible hack, try to remove this (ECR-22)
    #[doc(hidden)]
    pub fn set_from(&mut self, from: u16) {
        self.from = from
    }

    #[doc(hidden)]
    pub fn to(&self) -> u16 {
        self.to
    }

    /// Returns length of the `DBKey`.
    pub fn len(&self) -> u16 {
        self.to - self.from
    }

    /// Returns true if `DBKey` has zero length.
    pub fn is_empty(&self) -> bool {
        self.to == self.from
    }

    /// Get bit at position `idx`.
    pub fn get(&self, idx: u16) -> ChildKind {
        debug_assert!(self.from + idx < self.to);

        let pos = self.from + idx;
        let chunk = self.data[(pos / 8) as usize];
        let bit = 7 - pos % 8;
        let value = (1 << bit) & chunk;
        if value != 0 {
            ChildKind::Right
        } else {
            ChildKind::Left
        }
    }

    /// Shortens this DBKey to the specified length.
    pub fn prefix(&self, suffix: u16) -> DBKey {
        debug_assert!(self.from + suffix <= self.data.len() as u16 * 8);

        DBKey {
            data: self.data,
            from: self.from,
            to: self.from + suffix,
        }
    }

    /// Return object which represents a view on to this slice (further) offset by `i` bits.
    pub fn suffix(&self, suffix: u16) -> DBKey {
        debug_assert!(self.from + suffix <= self.to);

        DBKey {
            data: self.data,
            from: self.from + suffix,
            to: self.to,
        }
    }

    /// Shortens this DBKey to the specified length.
    pub fn truncate(&self, size: u16) -> DBKey {
        debug_assert!(self.from + size <= self.to);

        DBKey {
            data: self.data,
            from: self.from,
            to: self.from + size,
        }
    }

    /// Returns how many bits at the beginning matches with `other`
    pub fn common_prefix(&self, other: &Self) -> u16 {
        // We assume that all slices created from byte arrays with the same length
        if self.from != other.from {
            0
        } else {
            let from = self.from / 8;
            let to = min((self.to + 7) / 8, (other.to + 7) / 8);
            let max_len = min(self.len(), other.len());

            for i in from..to {
                let x = self.data[i as usize] ^ other.data[i as usize];
                if x != 0 {
                    let tail = x.leading_zeros() as u16;
                    return min(i * 8 + tail - self.from, max_len);
                }
            }
            max_len
        }
    }

    /// Returns true if we starts with the same prefix at the whole of `Other`
    pub fn starts_with(&self, other: &Self) -> bool {
        self.common_prefix(other) == other.len()
    }

    /// Returns true if self.to not changed
    pub fn is_leaf(&self) -> bool {
        self.to == (KEY_SIZE * 8) as u16
    }

    // TODO: terrible hack, try to remove this (ECR-22)
    /// Represents `DBKey` as byte array and returns it
    pub fn as_bytes(&self) -> Box<[u8]> {
        let mut buffer = Box::new([0u8; DB_KEY_SIZE as usize]);
        self.write(buffer.as_mut());
        buffer
    }
}

impl AsRef<[u8]> for DBKey {
    fn as_ref(&self) -> &[u8] {
        &self.data
    }
}

impl StorageKey for DBKey {
    fn size(&self) -> usize {
        DB_KEY_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        if self.is_leaf() {
            buffer[0] = LEAF_KEY_PREFIX;
            buffer[1..KEY_SIZE + 1].copy_from_slice(&self.data);
            buffer[KEY_SIZE + 1] = 0;
        } else {
            buffer[0] = BRANCH_KEY_PREFIX;
            let right = (self.to as usize + 7) / 8;
            buffer[1..right + 1].copy_from_slice(&self.data[0..right]);
            if self.to % 8 != 0 {
                buffer[right] &= !(255u8 >> (self.to % 8));
            }
            for i in buffer.iter_mut().take(KEY_SIZE + 1).skip(right + 1) {
                *i = 0
            }
            buffer[KEY_SIZE + 1] = self.to as u8;
        }
    }

    fn read(buffer: &[u8]) -> Self {
        debug_assert_eq!(buffer.len(), DB_KEY_SIZE);
        let mut data = [0; KEY_SIZE];
        data[..].copy_from_slice(&buffer[1..KEY_SIZE + 1]);
        let to = match buffer[0] {
            LEAF_KEY_PREFIX => KEY_SIZE as u16 * 8,
            BRANCH_KEY_PREFIX => u16::from(buffer[DB_KEY_SIZE - 1]),
            _ => unreachable!("wrong key prefix"),
        };
        DBKey {
            data: data,
            from: 0,
            to: to,
        }
    }
}

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

impl ::std::fmt::Debug for DBKey {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "DBKey(")?;
        for i in 0..self.len() {
            write!(
                f,
                "{}",
                match self.get(i) {
                    ChildKind::Left => '0',
                    ChildKind::Right => '1',
                }
            )?;
        }
        write!(f, ")")
    }
}

#[test]
fn test_dbkey_suffix() {
    let b = DBKey::read(b"\x00\x01\x02\xFF\x0C0000000000000000000000000000\x20");
    assert_eq!(b.len(), 32);
    assert_eq!(b.get(0), ChildKind::Left);
    assert_eq!(b.get(7), ChildKind::Right);
    assert_eq!(b.get(8), ChildKind::Left);
    assert_eq!(b.get(14), ChildKind::Right);
    assert_eq!(b.get(15), ChildKind::Left);
    assert_eq!(b.get(16), ChildKind::Right);
    assert_eq!(b.get(20), ChildKind::Right);
    assert_eq!(b.get(23), ChildKind::Right);
    assert_eq!(b.get(31), ChildKind::Left);
    let b2 = b.suffix(8);
    assert_eq!(b2.len(), 24);
    assert_eq!(b2.get(0), ChildKind::Left);
    assert_eq!(b2.get(6), ChildKind::Right);
    assert_eq!(b2.get(7), ChildKind::Left);
    assert_eq!(b2.get(12), ChildKind::Right);
    assert_eq!(b2.get(15), ChildKind::Right);
    let b3 = b2.suffix(24);
    assert_eq!(b3.len(), 0);
    let b4 = b.suffix(1);
    assert_eq!(b4.get(6), ChildKind::Right);
    assert_eq!(b4.get(7), ChildKind::Left);
    assert_eq!(b4.get(13), ChildKind::Right);
}

#[test]
fn test_dbkey_truncate() {
    let b = DBKey::read(b"\x00\x80wertyuiopasdfghjklzxcvbnm123456\x08");
    assert_eq!(b.len(), 8);
    assert_eq!(b.truncate(1).get(0), ChildKind::Right);
    assert_eq!(b.truncate(1).len(), 1);
}

#[test]
fn test_dbkey_len() {
    let b = DBKey::read(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00");
    assert_eq!(b.len(), 256);
}

#[test]
#[should_panic(expected = "self.from + idx < self.to")]
fn test_dbkey_at_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\x0F");
    b.get(32);
}

#[test]
#[should_panic(expected = "self.from + suffix <= self.to")]
fn test_dbkey_suffix_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    assert_eq!(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00".len(), 34);
    b.suffix(255).suffix(2);
}

#[test]
#[should_panic(expected = "self.from + idx < self.to")]
fn test_dbkey_suffix_at_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    b.suffix(1).get(255);
}

#[test]
fn test_dbkey_common_prefix() {
    let b1 = DBKey::read(b"\x01abcd0000000000000000000000000000\x00");
    let b2 = DBKey::read(b"\x01abde0000000000000000000000000000\x00");
    assert_eq!(b1.common_prefix(&b1), 256);
    let c = b1.common_prefix(&b2);
    assert_eq!(c, 21);
    let c = b2.common_prefix(&b1);
    assert_eq!(c, 21);
    let b1 = b1.suffix(9);
    let b2 = b2.suffix(9);
    let c = b1.common_prefix(&b2);
    assert_eq!(c, 12);
    let b3 = DBKey::read(b"\x01\xFF0000000000000000000000000000000\x00");
    let b4 = DBKey::read(b"\x01\xFE0000000000000000000000000000000\x00");
    assert_eq!(b3.common_prefix(&b4), 7);
    assert_eq!(b4.common_prefix(&b3), 7);
    assert_eq!(b3.common_prefix(&b3), 256);
    let b3 = b3.suffix(30);
    assert_eq!(b3.common_prefix(&b3), 226);
    let b3 = b3.truncate(200);
    assert_eq!(b3.common_prefix(&b3), 200);
    let b5 = DBKey::read(b"\x01\xFF0000000000000000000000000000000\x00");
    assert_eq!(b5.truncate(0).common_prefix(&b3), 0);
}

#[test]
fn test_dbkey_is_leaf() {
    let b = DBKey::read(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00");
    assert_eq!(b.len(), 256);
    assert_eq!(b.suffix(4).is_leaf(), true);
    assert_eq!(b.suffix(8).is_leaf(), true);
    assert_eq!(b.suffix(250).is_leaf(), true);
    assert_eq!(b.truncate(16).is_leaf(), false);
}

#[test]
fn test_dbkey_is_branch() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    assert_eq!(b.len(), 255);
    assert_eq!(b.is_leaf(), false);
}
<commit_msg>Update proof keys prefixes declaration<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::min;

use crypto::{Hash, PublicKey, HASH_SIZE};
use super::super::StorageKey;

pub const BRANCH_KEY_PREFIX: u8 = 0;
pub const LEAF_KEY_PREFIX: u8 = 1;

/// Size in bytes of the `ProofMapKey`.
pub const KEY_SIZE: usize = HASH_SIZE;
pub const DB_KEY_SIZE: usize = KEY_SIZE + 2;

/// A trait that defines a subset of storage key types which are suitable for use with
/// `ProofMapIndex`.
///
/// The size of the keys must be exactly 32 bytes and the keys must have a uniform distribution.
pub trait ProofMapKey: StorageKey {}

impl ProofMapKey for Hash {}
impl ProofMapKey for PublicKey {}
impl ProofMapKey for [u8; KEY_SIZE] {}

impl StorageKey for [u8; KEY_SIZE] {
    fn size(&self) -> usize {
        KEY_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        buffer.copy_from_slice(self.as_ref())
    }

    fn read(buffer: &[u8]) -> Self {
        let mut value = [0; KEY_SIZE];
        value.copy_from_slice(buffer);
        value
    }
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ChildKind {
    Left,
    Right,
}

/// A struct that represents a bit slices of the proof map keys.
#[derive(Clone)]
pub struct DBKey {
    data: [u8; KEY_SIZE],
    from: u16,
    to: u16,
}

impl ::std::ops::Not for ChildKind {
    type Output = ChildKind;

    fn not(self) -> ChildKind {
        match self {
            ChildKind::Left => ChildKind::Right,
            ChildKind::Right => ChildKind::Left,
        }
    }
}

impl DBKey {
    /// Create a new bit slice from the given binary data.
    pub fn leaf<K: ProofMapKey>(key: &K) -> DBKey {
        debug_assert_eq!(key.size(), KEY_SIZE);

        let mut data = [0; KEY_SIZE];
        key.write(&mut data);
        DBKey {
            data: data,
            from: 0,
            to: (KEY_SIZE * 8) as u16,
        }
    }

    #[doc(hidden)]
    pub fn from(&self) -> u16 {
        self.from
    }

    // TODO: terrible hack, try to remove this (ECR-22)
    #[doc(hidden)]
    pub fn set_from(&mut self, from: u16) {
        self.from = from
    }

    #[doc(hidden)]
    pub fn to(&self) -> u16 {
        self.to
    }

    /// Returns length of the `DBKey`.
    pub fn len(&self) -> u16 {
        self.to - self.from
    }

    /// Returns true if `DBKey` has zero length.
    pub fn is_empty(&self) -> bool {
        self.to == self.from
    }

    /// Get bit at position `idx`.
    pub fn get(&self, idx: u16) -> ChildKind {
        debug_assert!(self.from + idx < self.to);

        let pos = self.from + idx;
        let chunk = self.data[(pos / 8) as usize];
        let bit = 7 - pos % 8;
        let value = (1 << bit) & chunk;
        if value != 0 {
            ChildKind::Right
        } else {
            ChildKind::Left
        }
    }

    /// Shortens this DBKey to the specified length.
    pub fn prefix(&self, suffix: u16) -> DBKey {
        debug_assert!(self.from + suffix <= self.data.len() as u16 * 8);

        DBKey {
            data: self.data,
            from: self.from,
            to: self.from + suffix,
        }
    }

    /// Return object which represents a view on to this slice (further) offset by `i` bits.
    pub fn suffix(&self, suffix: u16) -> DBKey {
        debug_assert!(self.from + suffix <= self.to);

        DBKey {
            data: self.data,
            from: self.from + suffix,
            to: self.to,
        }
    }

    /// Shortens this DBKey to the specified length.
    pub fn truncate(&self, size: u16) -> DBKey {
        debug_assert!(self.from + size <= self.to);

        DBKey {
            data: self.data,
            from: self.from,
            to: self.from + size,
        }
    }

    /// Returns how many bits at the beginning matches with `other`
    pub fn common_prefix(&self, other: &Self) -> u16 {
        // We assume that all slices created from byte arrays with the same length
        if self.from != other.from {
            0
        } else {
            let from = self.from / 8;
            let to = min((self.to + 7) / 8, (other.to + 7) / 8);
            let max_len = min(self.len(), other.len());

            for i in from..to {
                let x = self.data[i as usize] ^ other.data[i as usize];
                if x != 0 {
                    let tail = x.leading_zeros() as u16;
                    return min(i * 8 + tail - self.from, max_len);
                }
            }
            max_len
        }
    }

    /// Returns true if we starts with the same prefix at the whole of `Other`
    pub fn starts_with(&self, other: &Self) -> bool {
        self.common_prefix(other) == other.len()
    }

    /// Returns true if self.to not changed
    pub fn is_leaf(&self) -> bool {
        self.to == (KEY_SIZE * 8) as u16
    }

    // TODO: terrible hack, try to remove this (ECR-22)
    /// Represents `DBKey` as byte array and returns it
    pub fn as_bytes(&self) -> Box<[u8]> {
        let mut buffer = Box::new([0u8; DB_KEY_SIZE as usize]);
        self.write(buffer.as_mut());
        buffer
    }
}

impl AsRef<[u8]> for DBKey {
    fn as_ref(&self) -> &[u8] {
        &self.data
    }
}

impl StorageKey for DBKey {
    fn size(&self) -> usize {
        DB_KEY_SIZE
    }

    fn write(&self, buffer: &mut [u8]) {
        if self.is_leaf() {
            buffer[0] = LEAF_KEY_PREFIX;
            buffer[1..KEY_SIZE + 1].copy_from_slice(&self.data);
            buffer[KEY_SIZE + 1] = 0;
        } else {
            buffer[0] = BRANCH_KEY_PREFIX;
            let right = (self.to as usize + 7) / 8;
            buffer[1..right + 1].copy_from_slice(&self.data[0..right]);
            if self.to % 8 != 0 {
                buffer[right] &= !(255u8 >> (self.to % 8));
            }
            for i in buffer.iter_mut().take(KEY_SIZE + 1).skip(right + 1) {
                *i = 0
            }
            buffer[KEY_SIZE + 1] = self.to as u8;
        }
    }

    fn read(buffer: &[u8]) -> Self {
        debug_assert_eq!(buffer.len(), DB_KEY_SIZE);
        let mut data = [0; KEY_SIZE];
        data[..].copy_from_slice(&buffer[1..KEY_SIZE + 1]);
        let to = match buffer[0] {
            LEAF_KEY_PREFIX => KEY_SIZE as u16 * 8,
            BRANCH_KEY_PREFIX => u16::from(buffer[DB_KEY_SIZE - 1]),
            _ => unreachable!("wrong key prefix"),
        };
        DBKey {
            data: data,
            from: 0,
            to: to,
        }
    }
}

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

impl ::std::fmt::Debug for DBKey {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "DBKey(")?;
        for i in 0..self.len() {
            write!(
                f,
                "{}",
                match self.get(i) {
                    ChildKind::Left => '0',
                    ChildKind::Right => '1',
                }
            )?;
        }
        write!(f, ")")
    }
}

#[test]
fn test_dbkey_suffix() {
    let b = DBKey::read(b"\x00\x01\x02\xFF\x0C0000000000000000000000000000\x20");
    assert_eq!(b.len(), 32);
    assert_eq!(b.get(0), ChildKind::Left);
    assert_eq!(b.get(7), ChildKind::Right);
    assert_eq!(b.get(8), ChildKind::Left);
    assert_eq!(b.get(14), ChildKind::Right);
    assert_eq!(b.get(15), ChildKind::Left);
    assert_eq!(b.get(16), ChildKind::Right);
    assert_eq!(b.get(20), ChildKind::Right);
    assert_eq!(b.get(23), ChildKind::Right);
    assert_eq!(b.get(31), ChildKind::Left);
    let b2 = b.suffix(8);
    assert_eq!(b2.len(), 24);
    assert_eq!(b2.get(0), ChildKind::Left);
    assert_eq!(b2.get(6), ChildKind::Right);
    assert_eq!(b2.get(7), ChildKind::Left);
    assert_eq!(b2.get(12), ChildKind::Right);
    assert_eq!(b2.get(15), ChildKind::Right);
    let b3 = b2.suffix(24);
    assert_eq!(b3.len(), 0);
    let b4 = b.suffix(1);
    assert_eq!(b4.get(6), ChildKind::Right);
    assert_eq!(b4.get(7), ChildKind::Left);
    assert_eq!(b4.get(13), ChildKind::Right);
}

#[test]
fn test_dbkey_truncate() {
    let b = DBKey::read(b"\x00\x80wertyuiopasdfghjklzxcvbnm123456\x08");
    assert_eq!(b.len(), 8);
    assert_eq!(b.truncate(1).get(0), ChildKind::Right);
    assert_eq!(b.truncate(1).len(), 1);
}

#[test]
fn test_dbkey_len() {
    let b = DBKey::read(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00");
    assert_eq!(b.len(), 256);
}

#[test]
#[should_panic(expected = "self.from + idx < self.to")]
fn test_dbkey_at_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\x0F");
    b.get(32);
}

#[test]
#[should_panic(expected = "self.from + suffix <= self.to")]
fn test_dbkey_suffix_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    assert_eq!(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00".len(), 34);
    b.suffix(255).suffix(2);
}

#[test]
#[should_panic(expected = "self.from + idx < self.to")]
fn test_dbkey_suffix_at_overflow() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    b.suffix(1).get(255);
}

#[test]
fn test_dbkey_common_prefix() {
    let b1 = DBKey::read(b"\x01abcd0000000000000000000000000000\x00");
    let b2 = DBKey::read(b"\x01abde0000000000000000000000000000\x00");
    assert_eq!(b1.common_prefix(&b1), 256);
    let c = b1.common_prefix(&b2);
    assert_eq!(c, 21);
    let c = b2.common_prefix(&b1);
    assert_eq!(c, 21);
    let b1 = b1.suffix(9);
    let b2 = b2.suffix(9);
    let c = b1.common_prefix(&b2);
    assert_eq!(c, 12);
    let b3 = DBKey::read(b"\x01\xFF0000000000000000000000000000000\x00");
    let b4 = DBKey::read(b"\x01\xFE0000000000000000000000000000000\x00");
    assert_eq!(b3.common_prefix(&b4), 7);
    assert_eq!(b4.common_prefix(&b3), 7);
    assert_eq!(b3.common_prefix(&b3), 256);
    let b3 = b3.suffix(30);
    assert_eq!(b3.common_prefix(&b3), 226);
    let b3 = b3.truncate(200);
    assert_eq!(b3.common_prefix(&b3), 200);
    let b5 = DBKey::read(b"\x01\xFF0000000000000000000000000000000\x00");
    assert_eq!(b5.truncate(0).common_prefix(&b3), 0);
}

#[test]
fn test_dbkey_is_leaf() {
    let b = DBKey::read(b"\x01qwertyuiopasdfghjklzxcvbnm123456\x00");
    assert_eq!(b.len(), 256);
    assert_eq!(b.suffix(4).is_leaf(), true);
    assert_eq!(b.suffix(8).is_leaf(), true);
    assert_eq!(b.suffix(250).is_leaf(), true);
    assert_eq!(b.truncate(16).is_leaf(), false);
}

#[test]
fn test_dbkey_is_branch() {
    let b = DBKey::read(b"\x00qwertyuiopasdfghjklzxcvbnm123456\xFF");
    assert_eq!(b.len(), 255);
    assert_eq!(b.is_leaf(), false);
}
<|endoftext|>


<commit_before>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String,
    quiet: bool,
}

impl CommandAction {
    pub fn new(command_line: String, quiet: bool) -> CommandAction {
        CommandAction {
            command_line: command_line,
            quiet: quiet,
        }
    }

    pub fn get_command_line(&self, event: &Event) -> String {
        let path = match event.path {
            None => "",
            Some(ref path) => path.to_str().unwrap_or(""),
        };

        self.command_line.replace("{:p}", path)
    }

    pub fn get_command(&self, event: &Event) -> Command {
        let command_line = self.get_command_line(event);
        let mut cmd_pieces = command_line.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        command
    }
}

impl Action for CommandAction {
    fn handle_change(&self, event: &Event) -> Result<(), ()> {
        let mut command = self.get_command(event);

        if !self.quiet {
            command
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit());
        }

        let command_result = command.output();

        match command_result {
            Err(_) => {
                println!("Could not execute command: {:?}", self.command_line);
                Err(())
            }
            Ok(output) => {
                if !self.quiet {
                    println!("{}", String::from_utf8_lossy(&output.stdout));

                    if !output.stderr.is_empty() {
                        let write_result = writeln!(
                            &mut io::stderr(),
                            "{}",
                            String::from_utf8_lossy(&output.stderr)
                        );
                        match write_result {
                            Err(x) => println!("Error: Unable to write to stderr: {}", x),
                            Ok(_) => {}
                        }
                    }
                }

                Ok(())
            }
        }
    }
}

#[cfg(test)]
mod test {
    extern crate rand;

    use super::*;

    use actions::Action;
    use notify::{Event, Op};
    use std::path::PathBuf;

    #[test]
    fn constructor() {
        let _ = CommandAction::new("date".to_string(), false);
    }

    #[test]
    fn handle_change_existing_command() {
        let o = Op::empty();
        let path_buf = PathBuf::from("/");

        let event = Event {
            path: Some(path_buf),
            op: Ok(o),
        };

        // Assume the "date" command exists on all platforms
        let command = CommandAction::new("date".to_string(), true);
        let result = command.handle_change(&event);

        // We can't capture the output, so just make sure the function
        // returns Ok.
        assert!(result.is_ok());
    }

    #[test]
    fn handle_change_missing_command() {
        let o = Op::empty();
        let path_buf = PathBuf::from("/");

        let event = Event {
            path: Some(path_buf),
            op: Ok(o),
        };

        // Assume this command does not exist
        let command = CommandAction::new("command_does_not_exist".to_string(), true);
        let result = command.handle_change(&event);

        assert!(result.is_err());
    }

}
<commit_msg>Format code with cargo fmt<commit_after>use actions::Action;
use notify::Event;
use std::io::{self, Write};
use std::process::{Command, Stdio};

pub struct CommandAction {
    command_line: String,
    quiet: bool,
}

impl CommandAction {
    pub fn new(command_line: String, quiet: bool) -> CommandAction {
        CommandAction {
            command_line: command_line,
            quiet: quiet,
        }
    }

    pub fn get_command_line(&self, event: &Event) -> String {
        let path = match event.path {
            None => "",
            Some(ref path) => path.to_str().unwrap_or(""),
        };

        self.command_line.replace("{:p}", path)
    }

    pub fn get_command(&self, event: &Event) -> Command {
        let command_line = self.get_command_line(event);
        let mut cmd_pieces = command_line.split(" ");
        let mut command = Command::new(cmd_pieces.next().unwrap());
        for piece in cmd_pieces {
            command.arg(piece);
        }

        command
    }
}

impl Action for CommandAction {
    fn handle_change(&self, event: &Event) -> Result<(), ()> {
        let mut command = self.get_command(event);

        if !self.quiet {
            command
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit());
        }

        let command_result = command.output();

        match command_result {
            Err(_) => {
                println!("Could not execute command: {:?}", self.command_line);
                Err(())
            }
            Ok(output) => {
                if !self.quiet {
                    println!("{}", String::from_utf8_lossy(&output.stdout));

                    if !output.stderr.is_empty() {
                        let write_result = writeln!(
                            &mut io::stderr(),
                            "{}",
                            String::from_utf8_lossy(&output.stderr)
                        );
                        match write_result {
                            Err(x) => println!("Error: Unable to write to stderr: {}", x),
                            Ok(_) => {}
                        }
                    }
                }

                Ok(())
            }
        }
    }
}

#[cfg(test)]
mod test {
    extern crate rand;

    use super::*;

    use actions::Action;
    use notify::{Event, Op};
    use std::path::PathBuf;

    #[test]
    fn constructor() {
        let _ = CommandAction::new("date".to_string(), false);
    }

    #[test]
    fn handle_change_existing_command() {
        let o = Op::empty();
        let path_buf = PathBuf::from("/");

        let event = Event {
            path: Some(path_buf),
            op: Ok(o),
        };

        // Assume the "date" command exists on all platforms
        let command = CommandAction::new("date".to_string(), true);
        let result = command.handle_change(&event);

        // We can't capture the output, so just make sure the function
        // returns Ok.
        assert!(result.is_ok());
    }

    #[test]
    fn handle_change_missing_command() {
        let o = Op::empty();
        let path_buf = PathBuf::from("/");

        let event = Event {
            path: Some(path_buf),
            op: Ok(o),
        };

        // Assume this command does not exist
        let command = CommandAction::new("command_does_not_exist".to_string(), true);
        let result = command.handle_change(&event);

        assert!(result.is_err());
    }
}
<|endoftext|>