<commit_before>use error::*;
use std::fmt;
use std::rc::Rc;
use token::Literal;

#[derive(Clone, Debug)]
pub enum Expr {
    Func(Function),
    Atom(Atom),
    List(List),
    Quote(Quote),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Atom {
    Bool(bool),
    Int(i64),
    Flt(f64),
    Str(String),
    Sym(Symbol),
}

#[derive(Clone, Debug)]
pub struct List(pub Vec<Expr>);

#[derive(Clone, Debug)]
pub struct Quote(pub Vec<Expr>);

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Symbol(pub String);

#[derive(Clone)]
pub struct Function {
    name: Option<String>,
    func: Rc<Lambda>,
}

pub type Lambda = Box<Fn(&[Expr]) -> Result<Expr>>;

impl Expr {
    pub fn eval(&self) -> Result<Expr> {
        if let &Expr::List(ref lst) = self {
            if let Some((first, rest)) = lst.0.split_first() {
                if let &Expr::Func(ref func) = first {
                    return func.call(rest)
                } else {
                    return Err("expected function call".into())
                }
            }
        }
        Ok(self.clone())
    }

    pub fn atom(&self) -> Option<&Atom> {
        if let &Expr::Atom(ref x) = self { Some(x) } else { None }
    }

    pub fn list(&self) -> Option<&List> {
        if let &Expr::List(ref x) = self { Some(x) } else { None }
    }

    pub fn quote(&self) -> Option<&Quote> {
        if let &Expr::Quote(ref x) = self { Some(x) } else { None }
    }

    pub fn func(&self) -> Option<&Function> {
        if let &Expr::Func(ref x) = self { Some(x) } else { None }
    }
}

impl Atom {
    pub fn is_boolean(&self) -> bool {
        self.boolean().is_some()
    }

    pub fn is_int(&self) -> bool {
        self.int().is_some()
    }

    pub fn is_flt(&self) -> bool {
        self.flt().is_some()
    }

    pub fn is_str(&self) -> bool {
        self.str().is_some()
    }

    pub fn boolean(&self) -> Option<bool> {
        if let &Atom::Bool(x) = self { Some(x) } else { None }
    }

    pub fn int(&self) -> Option<i64> {
        if let &Atom::Int(x) = self { Some(x) } else { None }
    }

    pub fn flt(&self) -> Option<f64> {
        if let &Atom::Flt(x) = self { Some(x) } else { None }
    }

    pub fn str(&self) -> Option<&str> {
        if let &Atom::Str(ref x) = self { Some(x) } else { None }
    }
}

impl Function {
    pub fn new<S>(name: Option<S>, func: Lambda) -> Self
        where S: Into<String>
    {
        Function {
            name: name.map(Into::into),
            func: Rc::new(func),
        }
    }

    pub fn call<'a>(&self, args: &'a [Expr]) -> Result<Expr> {
        (self.func)(args)
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref name) = self.name {
            write!(f, "#[{}]", name)
        } else {
            write!(f, "#\u{03BB}")
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Func(ref func) => write!(f, "{}", func),
            Expr::Atom(ref atom) => write!(f, "{}", atom),
            Expr::List(ref list) => write!(f, "{}", list),
            Expr::Quote(ref quote) => write!(f, "{}", quote),
        }
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Bool(boolean) => write!(f, "#{}", if boolean { "t" } else { "f" }),
            Atom::Int(int) => write!(f, "{}", int),
            Atom::Flt(flt) => write!(f, "{}", flt),
            Atom::Str(ref string) => write!(f, "\"{}\"", string),
            Atom::Sym(ref sym) => write!(f, "#{}", sym.0),
        }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(");
        let mut iter = self.0.iter();
        iter.next().map(|x| write!(f, "{}", x));
        for expr in iter {
            write!(f, " {}", expr);
        }
        write!(f, ")")
    }
}

impl fmt::Display for Quote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[");
        let mut iter = self.0.iter();
        iter.next().map(|x| write!(f, "{}", x));
        for expr in iter {
            write!(f, " {}", expr);
        }
        write!(f, "]")
    }
}

impl fmt::Display for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl<T> From<T> for Expr
    where T: Into<Atom>
{
    fn from(x: T) -> Expr {
        Expr::Atom(x.into())
    }
}

impl From<Function> for Expr {
    fn from(x: Function) -> Expr {
        Expr::Func(x)
    }
}

impl<T> From<T> for Atom
    where T: Into<Literal>
{
    fn from(x: T) -> Self {
        match x.into() {
            Literal::Bool(y) => Atom::Bool(y),
            Literal::Int(y) => Atom::Int(y),
            Literal::Flt(y) => Atom::Flt(y),
            Literal::Str(y) => Atom::Str(y),
        }
    }
}

impl From<Symbol> for Atom {
    fn from(x: Symbol) -> Self {
        Atom::Sym(x)
    }
}

impl From<Quote> for List {
    fn from(x: Quote) -> Self {
        List(x.0)
    }
}

impl From<List> for Quote {
    fn from(x: List) -> Self {
        Quote(x.0)
    }
}

fn lift(func: Box<Fn(&[Atom]) -> Result<Atom>>) -> Lambda {
    Box::new(move |args| {
        func(args.iter()
                .map(|arg| {
                    if let &Expr::Atom(ref atom) = arg {
                        atom.clone()
                    } else {
                        panic!()
                    }
                })
                .collect::<Vec<_>>()
                .as_slice())
            .map(Expr::Atom)
    })
}

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

    #[test]
    fn call_fn() {
        let func = Box::new(move |atoms: &[Atom]| {
            Ok(Atom::Int(atoms.iter()
                .map(|x| if let &Atom::Int(y) = x { y } else { panic!() })
                .sum()))
        });
        let add = Function::new(Some("add"), lift(func));
        add.call(vec![Expr::Atom(Atom::Int(1)), Expr::Atom(Atom::Int(2))].as_slice());
    }
}
<commit_msg>Improve list, quote printing<commit_after>use error::*;
use std::fmt;
use std::rc::Rc;
use token::Literal;

#[derive(Clone, Debug)]
pub enum Expr {
    Func(Function),
    Atom(Atom),
    List(List),
    Quote(Quote),
}

#[derive(Clone, Debug, PartialEq)]
pub enum Atom {
    Bool(bool),
    Int(i64),
    Flt(f64),
    Str(String),
    Sym(Symbol),
}

#[derive(Clone, Debug)]
pub struct List(pub Vec<Expr>);

#[derive(Clone, Debug)]
pub struct Quote(pub Vec<Expr>);

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Symbol(pub String);

#[derive(Clone)]
pub struct Function {
    name: Option<String>,
    func: Rc<Lambda>,
}

pub type Lambda = Box<Fn(&[Expr]) -> Result<Expr>>;

impl Expr {
    pub fn eval(&self) -> Result<Expr> {
        if let &Expr::List(ref lst) = self {
            if let Some((first, rest)) = lst.0.split_first() {
                if let &Expr::Func(ref func) = first {
                    return func.call(rest)
                } else {
                    return Err("expected function call".into())
                }
            }
        }
        Ok(self.clone())
    }

    pub fn atom(&self) -> Option<&Atom> {
        if let &Expr::Atom(ref x) = self { Some(x) } else { None }
    }

    pub fn list(&self) -> Option<&List> {
        if let &Expr::List(ref x) = self { Some(x) } else { None }
    }

    pub fn quote(&self) -> Option<&Quote> {
        if let &Expr::Quote(ref x) = self { Some(x) } else { None }
    }

    pub fn func(&self) -> Option<&Function> {
        if let &Expr::Func(ref x) = self { Some(x) } else { None }
    }
}

impl Atom {
    pub fn is_boolean(&self) -> bool {
        self.boolean().is_some()
    }

    pub fn is_int(&self) -> bool {
        self.int().is_some()
    }

    pub fn is_flt(&self) -> bool {
        self.flt().is_some()
    }

    pub fn is_str(&self) -> bool {
        self.str().is_some()
    }

    pub fn boolean(&self) -> Option<bool> {
        if let &Atom::Bool(x) = self { Some(x) } else { None }
    }

    pub fn int(&self) -> Option<i64> {
        if let &Atom::Int(x) = self { Some(x) } else { None }
    }

    pub fn flt(&self) -> Option<f64> {
        if let &Atom::Flt(x) = self { Some(x) } else { None }
    }

    pub fn str(&self) -> Option<&str> {
        if let &Atom::Str(ref x) = self { Some(x) } else { None }
    }
}

impl Function {
    pub fn new<S>(name: Option<S>, func: Lambda) -> Self
        where S: Into<String>
    {
        Function {
            name: name.map(Into::into),
            func: Rc::new(func),
        }
    }

    pub fn call<'a>(&self, args: &'a [Expr]) -> Result<Expr> {
        (self.func)(args)
    }
}

impl fmt::Debug for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref name) = self.name {
            write!(f, "#[{}]", name)
        } else {
            write!(f, "#\u{03BB}")
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Expr::Func(ref func) => write!(f, "{}", func),
            Expr::Atom(ref atom) => write!(f, "{}", atom),
            Expr::List(ref list) => write!(f, "{}", list),
            Expr::Quote(ref quote) => write!(f, "{}", quote),
        }
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Atom::Bool(boolean) => write!(f, "#{}", if boolean { "t" } else { "f" }),
            Atom::Int(int) => write!(f, "{}", int),
            Atom::Flt(flt) => write!(f, "{}", flt),
            Atom::Str(ref string) => write!(f, "\"{}\"", string),
            Atom::Sym(ref sym) => write!(f, "#{}", sym.0),
        }
    }
}

impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({})", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Quote {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.split_first()
            .map(|(first, rest)| {
                rest.iter().fold(first.to_string(), |mut acc, x| {
                    acc.push(' ');
                    acc.push_str(&x.to_string());
                    acc
                })
            }).unwrap_or(String::new())
        )
    }
}

impl fmt::Display for Function {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(self, f)
    }
}

impl<T> From<T> for Expr
    where T: Into<Atom>
{
    fn from(x: T) -> Expr {
        Expr::Atom(x.into())
    }
}

impl From<Function> for Expr {
    fn from(x: Function) -> Expr {
        Expr::Func(x)
    }
}

impl<T> From<T> for Atom
    where T: Into<Literal>
{
    fn from(x: T) -> Self {
        match x.into() {
            Literal::Bool(y) => Atom::Bool(y),
            Literal::Int(y) => Atom::Int(y),
            Literal::Flt(y) => Atom::Flt(y),
            Literal::Str(y) => Atom::Str(y),
        }
    }
}

impl From<Symbol> for Atom {
    fn from(x: Symbol) -> Self {
        Atom::Sym(x)
    }
}

impl From<Quote> for List {
    fn from(x: Quote) -> Self {
        List(x.0)
    }
}

impl From<List> for Quote {
    fn from(x: List) -> Self {
        Quote(x.0)
    }
}

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

    fn lift(func: Box<Fn(&[Atom]) -> Result<Atom>>) -> Lambda {
        Box::new(move |args| {
            func(args.iter()
                    .map(|arg| {
                        if let &Expr::Atom(ref atom) = arg {
                            atom.clone()
                        } else {
                            panic!()
                        }
                    })
                    .collect::<Vec<_>>()
                    .as_slice())
                .map(Expr::Atom)
        })
    }

    #[test]
    fn call_fn() {
        let func = Box::new(move |atoms: &[Atom]| {
            Ok(Atom::Int(atoms.iter()
                .map(|x| if let &Atom::Int(y) = x { y } else { panic!() })
                .sum()))
        });
        let add = Function::new(Some("add"), lift(func));
        add.call(vec![Expr::Atom(Atom::Int(1)), Expr::Atom(Atom::Int(2))].as_slice());
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// 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.

//! Implementation of the chain block acceptance (or refusal) pipeline.

use secp;
use time;

use core::consensus;
use core::core::hash::Hash;
use core::core::{BlockHeader, Block, Proof};
use core::pow;
use types;
use types::{Tip, ChainStore};
use store;

bitflags! {
  /// Options for block validation
  pub flags Options: u32 {
    const NONE = 0b00000001,
    /// Runs with the easier version of the Proof of Work, mostly to make testing easier.
    const EASY_POW = 0b00000010,
  }
}

/// Contextual information required to process a new block and either reject or
/// accept it.
pub struct BlockContext<'a> {
	opts: Options,
	store: &'a ChainStore,
	head: Tip,
	tip: Option<Tip>,
}

#[derive(Debug)]
pub enum Error {
	/// The block doesn't fit anywhere in our chain
	Unfit(String),
	/// Target is too high either compared to ours or the block PoW hash
	TargetTooHigh,
	/// The proof of work is invalid
	InvalidPow,
	/// The block doesn't sum correctly or a tx signature is invalid
	InvalidBlockProof(secp::Error),
	/// Block time is too old
	InvalidBlockTime,
	/// Internal issue when trying to save or load data from store
	StoreErr(types::Error),
}

pub fn process_block(b: &Block, store: &ChainStore, opts: Options) -> Result<(), Error> {
	// TODO should just take a promise for a block with a full header so we don't
	// spend resources reading the full block when its header is invalid

	let head = try!(store.head().map_err(&Error::StoreErr));
	let mut ctx = BlockContext {
		opts: opts,
		store: store,
		head: head,
		tip: None,
	};

	try!(validate_header(&b, &mut ctx));
	try!(set_tip(&b.header, &mut ctx));
	try!(validate_block(b, &mut ctx));
	try!(add_block(b, &mut ctx));
	try!(update_tips(&mut ctx));
	Ok(())
}

// block processing pipeline
// 1. is the header valid (time, PoW, etc.)
// 2. is it the next head, a new fork, or extension of a fork (not a too old
// fork tho)
// 3. ok fine, is all of it valid (txs, merkle, utxo merkle, etc.)
// 4. add the sucker to the head/fork
// 5. did we increase a fork difficulty over the head?
// 6. ok fine, swap them up (can be tricky, think addresses invalidation)

/// First level of black validation that only needs to act on the block header
/// to make it as cheap as possible. The different validations are also
/// arranged by order of cost to have as little DoS surface as possible.
/// TODO require only the block header (with length information)
fn validate_header(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	let header = &b.header;
	if header.height > ctx.head.height + 1 {
		// TODO actually handle orphans and add them to a size-limited set
		return Err(Error::Unfit("orphan".to_string()));
	}

	let prev = try!(ctx.store.get_block_header(&header.previous).map_err(&Error::StoreErr));

	if header.timestamp <= prev.timestamp {
		// prevent time warp attacks and some timestamp manipulations by forcing strict
		// time progression
		return Err(Error::InvalidBlockTime);
	}
	if header.timestamp >
	   time::now() + time::Duration::seconds(12 * (consensus::BLOCK_TIME_SEC as i64)) {
		// refuse blocks too far in future, constant of 12 comes from bitcoin (2h worth
		// of blocks)
		// TODO add warning in p2p code if local time is too different from peers
		return Err(Error::InvalidBlockTime);
	}

	let (diff_target, cuckoo_sz) = consensus::next_target(header.timestamp.to_timespec().sec,
	                                                      prev.timestamp.to_timespec().sec,
	                                                      prev.target,
	                                                      prev.cuckoo_len);
	if header.target > diff_target {
		return Err(Error::TargetTooHigh);
	}

	if ctx.opts.intersects(EASY_POW) {
		if !pow::verify_size(b, 15) {
			return Err(Error::InvalidPow);
		}
	} else if !pow::verify_size(b, cuckoo_sz as u32) {
		return Err(Error::InvalidPow);
	}

	Ok(())
}

fn set_tip(h: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.tip = Some(ctx.head.clone());
	Ok(())
}

fn validate_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	// TODO check tx merkle tree
	let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	try!(b.verify(&curve).map_err(&Error::InvalidBlockProof));
	Ok(())
}

fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.tip = ctx.tip.as_ref().map(|t| t.append(b.hash()));
	ctx.store.save_block(b).map_err(&Error::StoreErr)
}

fn update_tips(ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.store.save_head(ctx.tip.as_ref().unwrap()).map_err(&Error::StoreErr)
}
<commit_msg>Clarifying comment for rejection of blocks too far in future.<commit_after>// Copyright 2016 The Grin Developers
//
// 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.

//! Implementation of the chain block acceptance (or refusal) pipeline.

use secp;
use time;

use core::consensus;
use core::core::hash::Hash;
use core::core::{BlockHeader, Block, Proof};
use core::pow;
use types;
use types::{Tip, ChainStore};
use store;

bitflags! {
  /// Options for block validation
  pub flags Options: u32 {
    const NONE = 0b00000001,
    /// Runs with the easier version of the Proof of Work, mostly to make testing easier.
    const EASY_POW = 0b00000010,
  }
}

/// Contextual information required to process a new block and either reject or
/// accept it.
pub struct BlockContext<'a> {
	opts: Options,
	store: &'a ChainStore,
	head: Tip,
	tip: Option<Tip>,
}

#[derive(Debug)]
pub enum Error {
	/// The block doesn't fit anywhere in our chain
	Unfit(String),
	/// Target is too high either compared to ours or the block PoW hash
	TargetTooHigh,
	/// The proof of work is invalid
	InvalidPow,
	/// The block doesn't sum correctly or a tx signature is invalid
	InvalidBlockProof(secp::Error),
	/// Block time is too old
	InvalidBlockTime,
	/// Internal issue when trying to save or load data from store
	StoreErr(types::Error),
}

pub fn process_block(b: &Block, store: &ChainStore, opts: Options) -> Result<(), Error> {
	// TODO should just take a promise for a block with a full header so we don't
	// spend resources reading the full block when its header is invalid

	let head = try!(store.head().map_err(&Error::StoreErr));
	let mut ctx = BlockContext {
		opts: opts,
		store: store,
		head: head,
		tip: None,
	};

	try!(validate_header(&b, &mut ctx));
	try!(set_tip(&b.header, &mut ctx));
	try!(validate_block(b, &mut ctx));
	try!(add_block(b, &mut ctx));
	try!(update_tips(&mut ctx));
	Ok(())
}

// block processing pipeline
// 1. is the header valid (time, PoW, etc.)
// 2. is it the next head, a new fork, or extension of a fork (not a too old
// fork tho)
// 3. ok fine, is all of it valid (txs, merkle, utxo merkle, etc.)
// 4. add the sucker to the head/fork
// 5. did we increase a fork difficulty over the head?
// 6. ok fine, swap them up (can be tricky, think addresses invalidation)

/// First level of black validation that only needs to act on the block header
/// to make it as cheap as possible. The different validations are also
/// arranged by order of cost to have as little DoS surface as possible.
/// TODO require only the block header (with length information)
fn validate_header(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	let header = &b.header;
	if header.height > ctx.head.height + 1 {
		// TODO actually handle orphans and add them to a size-limited set
		return Err(Error::Unfit("orphan".to_string()));
	}

	let prev = try!(ctx.store.get_block_header(&header.previous).map_err(&Error::StoreErr));

	if header.timestamp <= prev.timestamp {
		// prevent time warp attacks and some timestamp manipulations by forcing strict
		// time progression
		return Err(Error::InvalidBlockTime);
	}
	if header.timestamp >
	   time::now() + time::Duration::seconds(12 * (consensus::BLOCK_TIME_SEC as i64)) {
		// refuse blocks more than 12 blocks intervals in future (as in bitcoin)
		// TODO add warning in p2p code if local time is too different from peers
		return Err(Error::InvalidBlockTime);
	}

	let (diff_target, cuckoo_sz) = consensus::next_target(header.timestamp.to_timespec().sec,
	                                                      prev.timestamp.to_timespec().sec,
	                                                      prev.target,
	                                                      prev.cuckoo_len);
	if header.target > diff_target {
		return Err(Error::TargetTooHigh);
	}

	if ctx.opts.intersects(EASY_POW) {
		if !pow::verify_size(b, 15) {
			return Err(Error::InvalidPow);
		}
	} else if !pow::verify_size(b, cuckoo_sz as u32) {
		return Err(Error::InvalidPow);
	}

	Ok(())
}

fn set_tip(h: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.tip = Some(ctx.head.clone());
	Ok(())
}

fn validate_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	// TODO check tx merkle tree
	let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
	try!(b.verify(&curve).map_err(&Error::InvalidBlockProof));
	Ok(())
}

fn add_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.tip = ctx.tip.as_ref().map(|t| t.append(b.hash()));
	ctx.store.save_block(b).map_err(&Error::StoreErr)
}

fn update_tips(ctx: &mut BlockContext) -> Result<(), Error> {
	ctx.store.save_head(ctx.tip.as_ref().unwrap()).map_err(&Error::StoreErr)
}
<|endoftext|>


<commit_before>/*extern crate hyper;
extern crate rustc_serialize;*/

//use std::io;
use std::io::Read;

use super::rustc_serialize::json;
use super::rustc_serialize::Decodable;

use super::hyper::Client;
use super::hyper::header::Connection;

static BASE_PATH: &'static str = "https://api.telegram.org/";

pub struct Bot {
    api_key: String
}

#[derive(RustcDecodable)]
struct _GetMeResult {
    id: i32,
    first_name: String,
    username: String
}

#[derive(RustcDecodable)]
pub struct GetMe {
    ok: bool,
    result: _GetMeResult
}

impl Bot {
    pub fn new(api_key: &str) -> Bot {
        Bot {
            api_key: api_key.to_string()
        }
    }

    pub fn get_me(&self) -> String {
        let path = format!("{}bot{}/getMe", BASE_PATH, self.api_key);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }

    pub fn send_message(&self, chat_id: i32, text: String) -> String {
        let path = format!("{}bot{}/sendMessage?chat_id={}&text={}", BASE_PATH, self.api_key, chat_id, text);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }
}<commit_msg>fix some minor scope problems<commit_after>/*extern crate hyper;
extern crate rustc_serialize;*/

//use std::io;
use std::io::Read;

use super::rustc_serialize::json;
use super::rustc_serialize::Decodable;

use super::hyper::Client;
use super::hyper::header::Connection;

static BASE_PATH: &'static str = "https://api.telegram.org/";

pub struct Bot {
    api_key: String
}

#[derive(RustcDecodable)]
struct _GetMeResult {
    id: i32,
    first_name: String,
    username: String
}

#[derive(RustcDecodable)]
pub struct GetMe {
    pub ok: bool,
    pub result: _GetMeResult
}

impl Bot {
    pub fn new(api_key: &str) -> Bot {
        Bot {
            api_key: api_key.to_string()
        }
    }

    pub fn get_me(&self) -> String {
        let path = format!("{}bot{}/getMe", BASE_PATH, self.api_key);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }

    pub fn send_message(&self, chat_id: i32, text: String) -> String {
        let path = format!("{}bot{}/sendMessage?chat_id={}&text={}", BASE_PATH, self.api_key, chat_id, text);
        let client = Client::new();
        let mut res = client.get(&path)
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        return body;
    }
}<|endoftext|>


<commit_before>use std;
use image::Image;
use model::Model;
use super::PerfStatus;

pub fn filter_cpu1(in_img: Image, model: &Model, perf: &mut PerfStatus) -> Image {

    let mut in_maps: Vec<Vec<f32>> = Vec::new();
    let mut out_maps = in_img.data;
    let mut width = in_img.width;
    let mut width_stride = in_img.strides[0];
    let mut height = in_img.height;

    for layer in model.iter() {
        in_maps = out_maps;
        out_maps = Vec::new();

        let new_width = width - 2;
        let new_height = height - 2;

        unsafe {
            for i in 0..layer.nOutputPlane {
                let bias = &layer.bias[i as usize];
                let weights = &layer.weight[i as usize];
                let mut out: Vec<f32> = Vec::with_capacity(new_width * new_height);
                out.set_len(new_width * new_height);

                for j in 0..layer.nInputPlane as usize {
                    let in_map = in_maps.get_unchecked(j);
                    let w = weights.get_unchecked(j);
                    let w00 = *w.get_unchecked(0).get_unchecked(0);
                    let w01 = *w.get_unchecked(0).get_unchecked(1);
                    let w02 = *w.get_unchecked(0).get_unchecked(2);
                    let w10 = *w.get_unchecked(1).get_unchecked(0);
                    let w11 = *w.get_unchecked(1).get_unchecked(1);
                    let w12 = *w.get_unchecked(1).get_unchecked(2);
                    let w20 = *w.get_unchecked(2).get_unchecked(0);
                    let w21 = *w.get_unchecked(2).get_unchecked(1);
                    let w22 = *w.get_unchecked(2).get_unchecked(2);

                    for y in 0..new_height {
                        let off_src0 = y * width_stride;
                        let off_src1 = (y + 1) * width_stride;
                        let off_src2 = (y + 2) * width_stride;
                        let off_dst = y * new_width;
                        for x in 0..new_width {
                            *out.get_unchecked_mut(off_dst + x) +=
                                *in_map.get_unchecked(off_src0 + x + 0) * w00 +
                                *in_map.get_unchecked(off_src0 + x + 1) * w01 +
                                *in_map.get_unchecked(off_src0 + x + 2) * w02 +
                                *in_map.get_unchecked(off_src1 + x + 0) * w10 +
                                *in_map.get_unchecked(off_src1 + x + 1) * w11 +
                                *in_map.get_unchecked(off_src1 + x + 2) * w12 +
                                *in_map.get_unchecked(off_src2 + x + 0) * w20 +
                                *in_map.get_unchecked(off_src2 + x + 1) * w21 +
                                *in_map.get_unchecked(off_src2 + x + 2) * w22;
                        }
                    }
                }

                for j in 0..out.len() {
                    *out.get_unchecked_mut(j) = *out.get_unchecked(j) + bias;
                    if *out.get_unchecked(j) < 0.0 {
                        *out.get_unchecked_mut(j) *= 0.1;
                    }
                }
                out_maps.push(out);
            }
        }

        width = new_width;
        height = new_height;
        width_stride = width;
        perf.cnn_flo +=
            ((layer.nInputPlane * layer.nOutputPlane * layer.kW * layer.kH * 2) as u64 * (width * height) as u64) +
            (layer.nOutputPlane as u64 * width as u64 * height as u64);
    }

    let mut out_strides = Vec::new();
    for _ in 0..out_maps.len() {
        out_strides.push(width_stride);
    }
    Image {
        width: width,
        height: height,
        color_space: in_img.color_space.clone(),
        data: out_maps,
        strides: out_strides,
    }
}

pub fn filter_cpu2(in_img: Image, model: &Model, perf: &mut PerfStatus) -> Image {
    let stride = {
        let mut max_stride: usize = 1;
        for i in 0..model.len() as usize {
            let layer = &model[i];
            max_stride = std::cmp::max(max_stride, std::cmp::max(
                (in_img.width - i * 2) * layer.nInputPlane as usize,
                (in_img.width - (i + 1) * 2) * layer.nOutputPlane as usize));
        }
        max_stride
    };
    let mut buf = Vec::<f32>::with_capacity(stride * in_img.height);
    unsafe {
        let capacity = buf.capacity();
        buf.set_len(capacity);
    }

    {
        let cnt = model[0].nInputPlane as usize;
        for y in 0..in_img.height {
            let off = stride * y * cnt;
            for i in 0..cnt {
                let src_off = in_img.strides[i] * y;
                for x in 0..in_img.width {
                    buf[off + x * cnt + i] = in_img.data[i][src_off + x];
                }
            }
        }
    }

    let mut temp: [f32; 128] = [0.0; 128];
    let mut out_line: Vec<f32> = Vec::with_capacity(stride);
    unsafe { out_line.set_len(stride); }
    let (mut width, mut height) = (in_img.width, in_img.height);

    for layer in model.iter() {
        width = width - 2;
        height = height - 2;
        perf.cnn_flo +=
            ((layer.nInputPlane * layer.nOutputPlane * layer.kW * layer.kH * 2) as u64 * (width * height) as u64) +
            (layer.nOutputPlane as u64 * width as u64 * height as u64);

        let num_in = layer.nInputPlane as usize;
        let num_out = layer.nOutputPlane as usize;
        let bias = &layer.bias;

        let weights = {
            let mut w = Vec::with_capacity(layer.nInputPlane as usize);
            for i in 0..layer.nInputPlane as usize {
                let mut v = Vec::with_capacity(9 * layer.nOutputPlane as usize);
                for j in 0..layer.nOutputPlane as usize {
                    for x in 0..3 {
                        for y in 0..3 {
                            v.push(layer.weight[j][i][x][y]);
                        }
                    }
                }
                w.push(v);
            }
            w
        };

        unsafe {
            for y in 0..height {
                for x in 0..width {
                    let in_off00 = y * stride + x * num_in;
                    let in_off01 = in_off00 + num_in;
                    let in_off02 = in_off00 + num_in * 2;
                    let in_off10 = in_off00 + stride;
                    let in_off11 = in_off10 + num_in;
                    let in_off12 = in_off10 + num_in * 2;
                    let in_off20 = in_off00 + stride * 2;
                    let in_off21 = in_off20 + num_in;
                    let in_off22 = in_off20 + num_in * 2;

                    for i in 0..num_in {
                        let w = weights.get_unchecked(i);
                        let in00 = *buf.get_unchecked(in_off00 + i);
                        let in01 = *buf.get_unchecked(in_off01 + i);
                        let in02 = *buf.get_unchecked(in_off02 + i);
                        let in10 = *buf.get_unchecked(in_off10 + i);
                        let in11 = *buf.get_unchecked(in_off11 + i);
                        let in12 = *buf.get_unchecked(in_off12 + i);
                        let in20 = *buf.get_unchecked(in_off20 + i);
                        let in21 = *buf.get_unchecked(in_off21 + i);
                        let in22 = *buf.get_unchecked(in_off22 + i);
                        for j in 0..num_out {
                            let woff = j * 9;
                            *temp.get_unchecked_mut(j) +=
                                in00 * *w.get_unchecked(woff) +
                                in01 * *w.get_unchecked(woff + 1) +
                                in02 * *w.get_unchecked(woff + 2) +
                                in10 * *w.get_unchecked(woff + 3) +
                                in11 * *w.get_unchecked(woff + 4) +
                                in12 * *w.get_unchecked(woff + 5) +
                                in20 * *w.get_unchecked(woff + 6) +
                                in21 * *w.get_unchecked(woff + 7) +
                                in22 * *w.get_unchecked(woff + 8);
                        }
                    }

                    for i in 0..num_out {
                        let mut v = *temp.get_unchecked(i) + *bias.get_unchecked(i);
                        if v < 0.0 {
                            v *= 0.1;
                        }
                        *out_line.get_unchecked_mut(x * num_out + i) = v;
                        *temp.get_unchecked_mut(i) = 0.0;
                    }
                }

                let out_off = y * stride;
                for i in 0..width * num_out {
                    *buf.get_unchecked_mut(out_off + i) = *out_line.get_unchecked(i);
                }
            }
        }
    }

    let out_maps = {
        let mut out_maps = Vec::new();
        let num_out = model[model.len() - 1].nOutputPlane as usize;
        for i in 0..num_out {
            let mut v = Vec::with_capacity(width * height);
            unsafe { v.set_len(width * height); }
            for y in 0..height {
                let src_off = y * stride;
                let dst_off = y * width;
                for x in 0..width {
                    v[dst_off + x] = buf[src_off + x * num_out + i];
                }
            }
            out_maps.push(v);
        }
        out_maps
    };
    let out_strides = {
        let mut v = Vec::new();
        for _ in 0..out_maps.len() {
            v.push(width);
        }
        v
    };
    Image {
        width: width,
        height: height,
        color_space: in_img.color_space.clone(),
        data: out_maps,
        strides: out_strides,
    }
}
<commit_msg>Rust省メモリ実装: 一番内側のループをアンロール<commit_after>use std;
use image::Image;
use model::{Model, Layer};
use super::PerfStatus;

pub fn filter_cpu1(in_img: Image, model: &Model, perf: &mut PerfStatus) -> Image {

    let mut in_maps = in_img.data;
    let mut out_maps: Vec<Vec<f32>> = Vec::new();
    let mut width = in_img.width;
    let mut width_stride = in_img.strides[0];
    let mut height = in_img.height;

    for layer in model.iter() {
        let new_width = width - 2;
        let new_height = height - 2;

        unsafe {
            for i in 0..layer.nOutputPlane {
                let bias = &layer.bias[i as usize];
                let weights = &layer.weight[i as usize];
                let mut out: Vec<f32> = Vec::with_capacity(new_width * new_height);
                out.set_len(new_width * new_height);

                for j in 0..layer.nInputPlane as usize {
                    let in_map = in_maps.get_unchecked(j);
                    let w = weights.get_unchecked(j);
                    let w00 = *w.get_unchecked(0).get_unchecked(0);
                    let w01 = *w.get_unchecked(0).get_unchecked(1);
                    let w02 = *w.get_unchecked(0).get_unchecked(2);
                    let w10 = *w.get_unchecked(1).get_unchecked(0);
                    let w11 = *w.get_unchecked(1).get_unchecked(1);
                    let w12 = *w.get_unchecked(1).get_unchecked(2);
                    let w20 = *w.get_unchecked(2).get_unchecked(0);
                    let w21 = *w.get_unchecked(2).get_unchecked(1);
                    let w22 = *w.get_unchecked(2).get_unchecked(2);

                    for y in 0..new_height {
                        let off_src0 = y * width_stride;
                        let off_src1 = (y + 1) * width_stride;
                        let off_src2 = (y + 2) * width_stride;
                        let off_dst = y * new_width;
                        for x in 0..new_width {
                            *out.get_unchecked_mut(off_dst + x) +=
                                *in_map.get_unchecked(off_src0 + x + 0) * w00 +
                                *in_map.get_unchecked(off_src0 + x + 1) * w01 +
                                *in_map.get_unchecked(off_src0 + x + 2) * w02 +
                                *in_map.get_unchecked(off_src1 + x + 0) * w10 +
                                *in_map.get_unchecked(off_src1 + x + 1) * w11 +
                                *in_map.get_unchecked(off_src1 + x + 2) * w12 +
                                *in_map.get_unchecked(off_src2 + x + 0) * w20 +
                                *in_map.get_unchecked(off_src2 + x + 1) * w21 +
                                *in_map.get_unchecked(off_src2 + x + 2) * w22;
                        }
                    }
                }

                for j in 0..out.len() {
                    *out.get_unchecked_mut(j) = *out.get_unchecked(j) + bias;
                    if *out.get_unchecked(j) < 0.0 {
                        *out.get_unchecked_mut(j) *= 0.1;
                    }
                }
                out_maps.push(out);
            }
        }

        width = new_width;
        height = new_height;
        width_stride = width;
        perf.cnn_flo +=
            ((layer.nInputPlane * layer.nOutputPlane * layer.kW * layer.kH * 2) as u64 * (width * height) as u64) +
            (layer.nOutputPlane as u64 * width as u64 * height as u64);

        in_maps = out_maps;
        out_maps = Vec::new();
    }
    out_maps = in_maps;

    let mut out_strides = Vec::new();
    for _ in 0..out_maps.len() {
        out_strides.push(width_stride);
    }
    Image {
        width: width,
        height: height,
        color_space: in_img.color_space.clone(),
        data: out_maps,
        strides: out_strides,
    }
}

pub fn filter_cpu2(in_img: Image, model: &Model, perf: &mut PerfStatus) -> Image {
    let stride = {
        let mut max_stride: usize = 1;
        for i in 0..model.len() as usize {
            let layer = &model[i];
            max_stride = std::cmp::max(max_stride, std::cmp::max(
                (in_img.width - i * 2) * layer.nInputPlane as usize,
                (in_img.width - (i + 1) * 2) * layer.nOutputPlane as usize));
        }
        max_stride
    };
    let mut buf = Vec::<f32>::with_capacity(stride * in_img.height);
    unsafe {
        let capacity = buf.capacity();
        buf.set_len(capacity);
    }

    {
        let cnt = model[0].nInputPlane as usize;
        for y in 0..in_img.height {
            let off = stride * y * cnt;
            for i in 0..cnt {
                let src_off = in_img.strides[i] * y;
                for x in 0..in_img.width {
                    buf[off + x * cnt + i] = in_img.data[i][src_off + x];
                }
            }
        }
    }

    let mut temp: [f32; 128] = [0.0; 128];
    let mut out_line: Vec<f32> = Vec::with_capacity(stride);
    unsafe { out_line.set_len(stride); }
    let (mut width, mut height) = (in_img.width, in_img.height);

    for layer in model.iter() {
        width -= 2;
        height -= 2;
        perf.cnn_flo +=
            ((layer.nInputPlane * layer.nOutputPlane * layer.kW * layer.kH * 2) as u64 * (width * height) as u64) +
            (layer.nOutputPlane as u64 * width as u64 * height as u64);

        if layer.nOutputPlane < 32 {
            filter_cpu2_layer(layer, layer.nInputPlane as usize, layer.nOutputPlane as usize,
                              width, height, stride, &mut temp, &mut buf, &mut out_line);
        } else {
            filter_cpu2_layer_32(layer, layer.nInputPlane as usize, layer.nOutputPlane as usize,
                                 width, height, stride, &mut temp, &mut buf, &mut out_line);
        }
    }

    let out_maps = {
        let mut out_maps = Vec::new();
        let num_out = model[model.len() - 1].nOutputPlane as usize;
        for i in 0..num_out {
            let mut v = Vec::with_capacity(width * height);
            unsafe { v.set_len(width * height); }
            for y in 0..height {
                let src_off = y * stride;
                let dst_off = y * width;
                for x in 0..width {
                    v[dst_off + x] = buf[src_off + x * num_out + i];
                }
            }
            out_maps.push(v);
        }
        out_maps
    };
    let out_strides = {
        let mut v = Vec::new();
        for _ in 0..out_maps.len() {
            v.push(width);
        }
        v
    };
    Image {
        width: width,
        height: height,
        color_space: in_img.color_space.clone(),
        data: out_maps,
        strides: out_strides,
    }
}

fn filter_cpu2_layer(layer: &Layer, num_in: usize, num_out: usize,
                     width: usize, height: usize, stride: usize,
                     temp: &mut [f32; 128], buf: &mut Vec<f32>, out_line: &mut Vec<f32>) {
    let weights = filter_cpu2_get_weights(&layer);
    let mut input: [f32; 9] = [0.0; 9];
    unsafe {
        for y in 0..height {
            for x in 0..width {
                let in_off00 = y * stride + x * num_in;
                let in_off01 = in_off00 + num_in;
                let in_off02 = in_off00 + num_in * 2;
                let in_off10 = in_off00 + stride;
                let in_off11 = in_off10 + num_in;
                let in_off12 = in_off10 + num_in * 2;
                let in_off20 = in_off00 + stride * 2;
                let in_off21 = in_off20 + num_in;
                let in_off22 = in_off20 + num_in * 2;
                for i in 0..num_in {
                    let w = weights.get_unchecked(i);
                    *input.get_unchecked_mut(0) = *buf.get_unchecked(in_off00 + i);
                    *input.get_unchecked_mut(1) = *buf.get_unchecked(in_off01 + i);
                    *input.get_unchecked_mut(2) = *buf.get_unchecked(in_off02 + i);
                    *input.get_unchecked_mut(3) = *buf.get_unchecked(in_off10 + i);
                    *input.get_unchecked_mut(4) = *buf.get_unchecked(in_off11 + i);
                    *input.get_unchecked_mut(5) = *buf.get_unchecked(in_off12 + i);
                    *input.get_unchecked_mut(6) = *buf.get_unchecked(in_off20 + i);
                    *input.get_unchecked_mut(7) = *buf.get_unchecked(in_off21 + i);
                    *input.get_unchecked_mut(8) = *buf.get_unchecked(in_off22 + i);
                    for j in 0..num_out {
                        *temp.get_unchecked_mut(j) += convolve3x3(&input, &w, j * 9);
                    }
                }
                filter_cpu2_layer_bias_relu(&layer, num_out, x, temp, out_line);
            }
            filter_cpu2_layer_writeback_line(num_out, width, y, stride, buf, out_line);
        }
    }
}

fn filter_cpu2_layer_32(layer: &Layer, num_in: usize, num_out: usize,
                        width: usize, height: usize, stride: usize,
                        temp: &mut [f32; 128], buf: &mut Vec<f32>, out_line: &mut Vec<f32>) {
    let weights = filter_cpu2_get_weights(&layer);
    let mut input: [f32; 9] = [0.0; 9];
    unsafe {
        for y in 0..height {
            for x in 0..width {
                let in_off00 = y * stride + x * num_in;
                let in_off01 = in_off00 + num_in;
                let in_off02 = in_off00 + num_in * 2;
                let in_off10 = in_off00 + stride;
                let in_off11 = in_off10 + num_in;
                let in_off12 = in_off10 + num_in * 2;
                let in_off20 = in_off00 + stride * 2;
                let in_off21 = in_off20 + num_in;
                let in_off22 = in_off20 + num_in * 2;
                for i in 0..num_in {
                    let w = weights.get_unchecked(i);
                    *input.get_unchecked_mut(0) = *buf.get_unchecked(in_off00 + i);
                    *input.get_unchecked_mut(1) = *buf.get_unchecked(in_off01 + i);
                    *input.get_unchecked_mut(2) = *buf.get_unchecked(in_off02 + i);
                    *input.get_unchecked_mut(3) = *buf.get_unchecked(in_off10 + i);
                    *input.get_unchecked_mut(4) = *buf.get_unchecked(in_off11 + i);
                    *input.get_unchecked_mut(5) = *buf.get_unchecked(in_off12 + i);
                    *input.get_unchecked_mut(6) = *buf.get_unchecked(in_off20 + i);
                    *input.get_unchecked_mut(7) = *buf.get_unchecked(in_off21 + i);
                    *input.get_unchecked_mut(8) = *buf.get_unchecked(in_off22 + i);
                    for j in (0..num_out-7).step_by(8) {
                        let wi = j * 9;
                        *temp.get_unchecked_mut(j + 0) += convolve3x3(&input, &w, wi);
                        *temp.get_unchecked_mut(j + 1) += convolve3x3(&input, &w, wi + 9);
                        *temp.get_unchecked_mut(j + 2) += convolve3x3(&input, &w, wi + 18);
                        *temp.get_unchecked_mut(j + 3) += convolve3x3(&input, &w, wi + 27);
                        *temp.get_unchecked_mut(j + 4) += convolve3x3(&input, &w, wi + 36);
                        *temp.get_unchecked_mut(j + 5) += convolve3x3(&input, &w, wi + 45);
                        *temp.get_unchecked_mut(j + 6) += convolve3x3(&input, &w, wi + 54);
                        *temp.get_unchecked_mut(j + 7) += convolve3x3(&input, &w, wi + 63);
                    }
                }
                filter_cpu2_layer_bias_relu(&layer, num_out, x, temp, out_line);
            }
            filter_cpu2_layer_writeback_line(num_out, width, y, stride, buf, out_line);
        }
    }
}

#[inline(always)]
fn convolve3x3(input: &[f32; 9], w: &Vec<f32>, off: usize) -> f32 {
    unsafe {
        *input.get_unchecked(0) * *w.get_unchecked(off) +
            *input.get_unchecked(1) * *w.get_unchecked(off + 1) +
            *input.get_unchecked(2) * *w.get_unchecked(off + 2) +
            *input.get_unchecked(3) * *w.get_unchecked(off + 3) +
            *input.get_unchecked(4) * *w.get_unchecked(off + 4) +
            *input.get_unchecked(5) * *w.get_unchecked(off + 5) +
            *input.get_unchecked(6) * *w.get_unchecked(off + 6) +
            *input.get_unchecked(7) * *w.get_unchecked(off + 7) +
            *input.get_unchecked(8) * *w.get_unchecked(off + 8)
    }
}

fn filter_cpu2_get_weights(layer: &Layer) -> Vec<Vec<f32>> {
    let mut w = Vec::with_capacity(layer.nInputPlane as usize);
    for i in 0..layer.nInputPlane as usize {
        let mut v = Vec::with_capacity(9 * layer.nOutputPlane as usize);
        for j in 0..layer.nOutputPlane as usize {
            for x in 0..3 {
                for y in 0..3 {
                    v.push(layer.weight[j][i][x][y]);
                }
            }
        }
        w.push(v);
    }
    w
}

#[inline(always)]
fn filter_cpu2_layer_bias_relu(layer: &Layer, num_out: usize, x: usize,
                               temp: &mut [f32; 128], out_line: &mut Vec<f32>) {
    unsafe {
        for i in 0..num_out {
            let mut v = *temp.get_unchecked(i) + *layer.bias.get_unchecked(i);
            if v < 0.0 {
                v *= 0.1;
            }
            *out_line.get_unchecked_mut(x * num_out + i) = v;
            *temp.get_unchecked_mut(i) = 0.0;
        }
    }
}

#[inline(always)]
fn filter_cpu2_layer_writeback_line(num_out: usize, width: usize, y: usize, stride: usize,
                                    buf: &mut Vec<f32>, out_line: &mut Vec<f32>) {
    unsafe {
        let out_off = y * stride;
        for i in 0..width * num_out {
            *buf.get_unchecked_mut(out_off + i) = *out_line.get_unchecked(i);
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "rust")]
extern {
  fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
}

pub fn any(data: *const raw::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  klee_make_symbolic(data, length as libc::size_t, name_cstr.as_ptr());
}

pub fn i32(data: *const i32, name: &str) {
  unsafe { any(transmute(data), std::mem::sizeof::<i32>(), name); }
}

pub fn u32(data: *const u32, name: &str) {
  unsafe { any(transmute(data), std::mem::sizeof::<u32>(), name); }
}

pub fn i64(data: *const i64, name: &str) {
  unsafe { any(transmute(data), std::mem::sizeof::<i64>(), name); }
}

pub fn u64(data: *const u64, name: &str) {
  unsafe { any(transmute(data), std::mem::sizeof::<u64>(), name); }
}

pub fn str(data: &str, name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}

pub fn bytes(data: &[u8], name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}
<commit_msg>Update lib.rs<commit_after>extern crate libc;

use std::os::raw;
use std::ffi::CString;
use std::mem::{transmute, size_of};

#[link(name = "rust")]
extern {
  fn klee_make_symbolic(data: *const raw::c_void, length: libc::size_t, name: *const raw::c_char);
}

pub fn any(data: *const raw::c_void, length: usize, name: &str) {
  let name_cstr = CString::new(name).unwrap();
  klee_make_symbolic(data, length as libc::size_t, name_cstr.as_ptr());
}

pub fn i32(data: *const i32, name: &str) {
  unsafe { any(transmute(data), size_of::<i32>(), name); }
}

pub fn u32(data: *const u32, name: &str) {
  unsafe { any(transmute(data), size_of::<u32>(), name); }
}

pub fn i64(data: *const i64, name: &str) {
  unsafe { any(transmute(data), size_of::<i64>(), name); }
}

pub fn u64(data: *const u64, name: &str) {
  unsafe { any(transmute(data), size_of::<u64>(), name); }
}

pub fn str(data: &str, name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}

pub fn bytes(data: &[u8], name: &str) {
  unsafe { any(transmute(data.as_ptr()), data.len(), name); }
}
<|endoftext|>


<commit_before>//! Bindings to [libFuzzer](http://llvm.org/docs/LibFuzzer.html): a runtime for
//! coverage-guided fuzzing.
//!
//! See [the `cargo-fuzz`
//! guide](https://rust-fuzz.github.io/book/cargo-fuzz.html) for a usage
//! tutorial.
//!
//! The main export of this crate is [the `fuzz_target!`
//! macro](./macro.fuzz_target.html), which allows you to define targets for
//! libFuzzer to exercise.

#![deny(missing_docs, missing_debug_implementations)]

pub use arbitrary;

extern "C" {
    // We do not actually cross the FFI bound here.
    #[allow(improper_ctypes)]
    fn rust_fuzzer_test_input(input: &[u8]);
}

#[doc(hidden)]
#[export_name = "LLVMFuzzerTestOneInput"]
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
    let test_input = ::std::panic::catch_unwind(|| unsafe {
        let data_slice = ::std::slice::from_raw_parts(data, size);
        rust_fuzzer_test_input(data_slice);
    });
    if test_input.err().is_some() {
        // hopefully the custom panic hook will be called before and abort the
        // process before the stack frames are unwinded.
        ::std::process::abort();
    }
    0
}

#[doc(hidden)]
#[export_name = "LLVMFuzzerInitialize"]
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
    // Registers a panic hook that aborts the process before unwinding.
    // It is useful to abort before unwinding so that the fuzzer will then be
    // able to analyse the process stack frames to tell different bugs appart.
    //
    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
    // impossible to build code using compiler plugins with this flag.
    // We will be able to remove this code when
    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
    let default_hook = ::std::panic::take_hook();
    ::std::panic::set_hook(Box::new(move |panic_info| {
        default_hook(panic_info);
        ::std::process::abort();
    }));
    0
}

/// Define a fuzz target.
///
/// ## Example
///
/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
///
/// ```no_run
/// #![no_main]
///
/// use libfuzzer_sys::fuzz_target;
///
/// // Note: `|input|` is short for `|input: &[u8]|`.
/// fuzz_target!(|input| {
///     let _result: Result<_, _> = my_crate::parse(input);
/// });
/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
/// ```
///
/// ## Arbitrary Input Types
///
/// The input is a `&[u8]` slice by default, but you can take arbitrary input
/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
///
/// For example, if you wanted to take an arbitrary RGB color, you could do the
/// following:
///
/// ```no_run
/// #![no_main]
///
/// use libfuzzer_sys::{arbitrary::{Arbitrary, Unstructured}, fuzz_target};
///
/// #[derive(Debug)]
/// pub struct Rgb {
///     r: u8,
///     g: u8,
///     b: u8,
/// }
///
/// impl Arbitrary for Rgb {
///     fn arbitrary<U>(raw: &mut U) -> Result<Self, U::Error>
///     where
///         U: Unstructured + ?Sized
///     {
///         let mut buf = [0; 3];
///         raw.fill_buffer(&mut buf)?;
///         let r = buf[0];
///         let g = buf[1];
///         let b = buf[2];
///         Ok(Rgb { r, g, b })
///     }
/// }
///
/// // Write a fuzz target that works with RGB colors instead of raw bytes.
/// fuzz_target!(|color: Rgb| {
///     my_crate::convert_color(color);
/// });
/// # mod my_crate { fn convert_color(_: super::Rgb) {} }
#[macro_export]
macro_rules! fuzz_target {
    (|$bytes:ident| $body:block) => {
        #[no_mangle]
        pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
            // formatting of the input to that file. This is only intended for
            // `cargo fuzz`'s use!
            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
                use std::io::Write;
                let mut file = std::fs::File::create(path)
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
                writeln!(&mut file, "{:?}", $bytes)
                    .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
                return;
            }

            $body
        }
    };

    (|$data:ident: &[u8]| $body:block) => {
        fuzz_target!(|$data| $body);
    };

    (|$data:ident: $dty: ty| $body:block) => {
        #[no_mangle]
        pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
            use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};

            // Early exit if we don't have enough bytes for the `Arbitrary`
            // implementation. This helps the fuzzer avoid exploring all the
            // different not-enough-input-bytes paths inside the `Arbitrary`
            // implementation. Additionally, it exits faster, letting the fuzzer
            // get to longer inputs that actually lead to interesting executions
            // quicker.
            if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
                return;
            }

            let mut u = Unstructured::new(bytes);
            let data = <$dty as Arbitrary>::arbitrary_take_rest(u);

            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
            // formatting of the input to that file. This is only intended for
            // `cargo fuzz`'s use!
            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
                use std::io::Write;
                let mut file = std::fs::File::create(path)
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
                (match data {
                    Ok(data) => writeln!(&mut file, "{:#?}", data),
                    Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
                })
                .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
                return;
            }

            let $data = match data {
                Ok(d) => d,
                Err(_) => return,
            };

            $body
        }
    };
}
<commit_msg>Document `rust_fuzzer_test_input`<commit_after>//! Bindings to [libFuzzer](http://llvm.org/docs/LibFuzzer.html): a runtime for
//! coverage-guided fuzzing.
//!
//! See [the `cargo-fuzz`
//! guide](https://rust-fuzz.github.io/book/cargo-fuzz.html) for a usage
//! tutorial.
//!
//! The main export of this crate is [the `fuzz_target!`
//! macro](./macro.fuzz_target.html), which allows you to define targets for
//! libFuzzer to exercise.

#![deny(missing_docs, missing_debug_implementations)]

pub use arbitrary;

extern "C" {
    // We do not actually cross the FFI bound here.
    #[allow(improper_ctypes)]
    fn rust_fuzzer_test_input(input: &[u8]);
}

#[doc(hidden)]
#[export_name = "LLVMFuzzerTestOneInput"]
pub fn test_input_wrap(data: *const u8, size: usize) -> i32 {
    let test_input = ::std::panic::catch_unwind(|| unsafe {
        let data_slice = ::std::slice::from_raw_parts(data, size);
        rust_fuzzer_test_input(data_slice);
    });
    if test_input.err().is_some() {
        // hopefully the custom panic hook will be called before and abort the
        // process before the stack frames are unwinded.
        ::std::process::abort();
    }
    0
}

#[doc(hidden)]
#[export_name = "LLVMFuzzerInitialize"]
pub fn initialize(_argc: *const isize, _argv: *const *const *const u8) -> isize {
    // Registers a panic hook that aborts the process before unwinding.
    // It is useful to abort before unwinding so that the fuzzer will then be
    // able to analyse the process stack frames to tell different bugs appart.
    //
    // HACK / FIXME: it would be better to use `-C panic=abort` but it's currently
    // impossible to build code using compiler plugins with this flag.
    // We will be able to remove this code when
    // https://github.com/rust-lang/cargo/issues/5423 is fixed.
    let default_hook = ::std::panic::take_hook();
    ::std::panic::set_hook(Box::new(move |panic_info| {
        default_hook(panic_info);
        ::std::process::abort();
    }));
    0
}

/// Define a fuzz target.
///
/// ## Example
///
/// This example takes a `&[u8]` slice and attempts to parse it. The parsing
/// might fail and return an `Err`, but it shouldn't ever panic or segfault.
///
/// ```no_run
/// #![no_main]
///
/// use libfuzzer_sys::fuzz_target;
///
/// // Note: `|input|` is short for `|input: &[u8]|`.
/// fuzz_target!(|input| {
///     let _result: Result<_, _> = my_crate::parse(input);
/// });
/// # mod my_crate { pub fn parse(_: &[u8]) -> Result<(), ()> { unimplemented!() } }
/// ```
///
/// ## Arbitrary Input Types
///
/// The input is a `&[u8]` slice by default, but you can take arbitrary input
/// types, as long as the type implements [the `arbitrary` crate's `Arbitrary`
/// trait](https://docs.rs/arbitrary/*/arbitrary/trait.Arbitrary.html) (which is
/// also re-exported as `libfuzzer_sys::arbitrary::Arbitrary` for convenience).
///
/// For example, if you wanted to take an arbitrary RGB color, you could do the
/// following:
///
/// ```no_run
/// #![no_main]
///
/// use libfuzzer_sys::{arbitrary::{Arbitrary, Unstructured}, fuzz_target};
///
/// #[derive(Debug)]
/// pub struct Rgb {
///     r: u8,
///     g: u8,
///     b: u8,
/// }
///
/// impl Arbitrary for Rgb {
///     fn arbitrary<U>(raw: &mut U) -> Result<Self, U::Error>
///     where
///         U: Unstructured + ?Sized
///     {
///         let mut buf = [0; 3];
///         raw.fill_buffer(&mut buf)?;
///         let r = buf[0];
///         let g = buf[1];
///         let b = buf[2];
///         Ok(Rgb { r, g, b })
///     }
/// }
///
/// // Write a fuzz target that works with RGB colors instead of raw bytes.
/// fuzz_target!(|color: Rgb| {
///     my_crate::convert_color(color);
/// });
/// # mod my_crate { fn convert_color(_: super::Rgb) {} }
#[macro_export]
macro_rules! fuzz_target {
    (|$bytes:ident| $body:block) => {
        /// Auto-generated function
        #[no_mangle]
        pub extern "C" fn rust_fuzzer_test_input($bytes: &[u8]) {
            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
            // formatting of the input to that file. This is only intended for
            // `cargo fuzz`'s use!
            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
                use std::io::Write;
                let mut file = std::fs::File::create(path)
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
                writeln!(&mut file, "{:?}", $bytes)
                    .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
                return;
            }

            $body
        }
    };

    (|$data:ident: &[u8]| $body:block) => {
        fuzz_target!(|$data| $body);
    };

    (|$data:ident: $dty: ty| $body:block) => {
        #[no_mangle]
        pub extern "C" fn rust_fuzzer_test_input(bytes: &[u8]) {
            use libfuzzer_sys::arbitrary::{Arbitrary, Unstructured};

            // Early exit if we don't have enough bytes for the `Arbitrary`
            // implementation. This helps the fuzzer avoid exploring all the
            // different not-enough-input-bytes paths inside the `Arbitrary`
            // implementation. Additionally, it exits faster, letting the fuzzer
            // get to longer inputs that actually lead to interesting executions
            // quicker.
            if bytes.len() < <$dty as Arbitrary>::size_hint(0).0 {
                return;
            }

            let mut u = Unstructured::new(bytes);
            let data = <$dty as Arbitrary>::arbitrary_take_rest(u);

            // When `RUST_LIBFUZZER_DEBUG_PATH` is set, write the debug
            // formatting of the input to that file. This is only intended for
            // `cargo fuzz`'s use!
            if let Ok(path) = std::env::var("RUST_LIBFUZZER_DEBUG_PATH") {
                use std::io::Write;
                let mut file = std::fs::File::create(path)
                    .expect("failed to create `RUST_LIBFUZZER_DEBUG_PATH` file");
                (match data {
                    Ok(data) => writeln!(&mut file, "{:#?}", data),
                    Err(err) => writeln!(&mut file, "Arbitrary Error: {}", err),
                })
                .expect("failed to write to `RUST_LIBFUZZER_DEBUG_PATH` file");
                return;
            }

            let $data = match data {
                Ok(d) => d,
                Err(_) => return,
            };

            $body
        }
    };
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if 2d triangle list with color assigned per vertex is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba(&mut self, _vertices: &[f64], _colors: &[f64]) {}
}

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<commit_msg>Added triangle list f32<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! Attempt of creating a cheap drawing context.

use std::num::Float;

pub type Matrix2d = [f64, ..6];
pub type Color = [f64, ..4];

/// Implemented by all graphics back-ends.
/// This trait uses default methods to simplify implementation.
pub trait BackEnd {
    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f64(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f64(&mut self, _vertices: &[f64], _colors: &[f64]) {}

    /// Returns true if feature is supported.
    #[inline(always)]
    fn supports_tri_list_xy_rgba_f32(&self) -> bool { false }

    /// Renders list of 2d triangles with color assigned per vertex.
    fn tri_list_xy_rgba_f32(&mut self, _vertices: &[f32], _colors: &[f32]) {}
}

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

/// Multiplies two matrices.
#[inline(always)]
pub fn multiply(m: &[f64, ..6], b: &[f64, ..6]) -> [f64, ..6] {
    [m[0]*b[0]+m[1]*b[3]+m[2]*0.0,  m[0]*b[1]+m[1]*b[4]+m[2]*0.0,  m[0]*b[2]+m[1]*b[5]+m[2]*1.0,
     m[3]*b[0]+m[4]*b[3]+m[5]*0.0,  m[3]*b[1]+m[4]*b[4]+m[5]*0.0,  m[3]*b[2]+m[4]*b[5]+m[5]*1.0]
}

/// Drawing 2d context.
pub struct Context<'a> {
    base: Field<'a, Matrix2d>,
    transform: Field<'a, Matrix2d>,
    color: Field<'a, Color>,
}

impl<'a> Context<'a> {
    /// Creates a new drawing context.
    pub fn new() -> Context {
        Context {
            base:  Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            transform: Value([1.0, 0.0, 0.0,
                          0.0, 1.0, 0.0]),
            color: Value([0.0, 0.0, 0.0, 1.0]),
        }
    }

    /// Returns a translated context.
    #[inline(always)]
    pub fn trans(&'a self, x: f64, y: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let trans: [f64, ..6] = [1.0, 0.0, x,
                                         0.0, 1.0, y];
                 multiply(&trans, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Rotates with degrees.
    #[inline(always)]
    pub fn rot_deg(&'a self, angle: f64) -> Context<'a> {
        let pi: f64 = Float::pi();
        self.rot(angle * pi / 180.0)
    }

    /// Returns a rotated context.
    #[inline(always)]
    pub fn rot(&'a self, angle: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let c = angle.cos();
                let s = angle.sin();
                let rot: [f64, ..6] = [c, s, 0.0,
                                      -s, c, 0.0];
                multiply(&rot, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a scaled context.
    #[inline(always)]
    pub fn scale(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let scale: [f64, ..6] = [sx, 0.0, 0.0,
                                         0.0, sy, 0.0];
                multiply(&scale, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }

    /// Returns a sheared context.
    #[inline(always)]
    pub fn shear(&'a self, sx: f64, sy: f64) -> Context<'a> {
        Context {
            base: Borrowed(self.base.get()),
            transform: Value({
                let shear: [f64, ..6] = [1.0, sx, 0.0,
                                         sy, 1.0, 0.0];
            multiply(&shear, self.transform.get())
            }),
            color: Borrowed(self.color.get()),
        }
    }
}

#[test]
fn test_context() {
    let c = Context::new();
    {
        let d = c.trans(20.0, 40.0);
        let d = d.trans(10.0, 10.0);
        assert_eq!(d.transform.get()[2], 30.0);
        assert_eq!(d.transform.get()[5], 50.0);
    }
    assert_eq!(c.transform.get()[2], 0.0);
    assert_eq!(c.transform.get()[5], 0.0);

    let c = c.rot_deg(90.0);
    assert!((c.transform.get()[0] - 0.0).abs() < 0.00001);
    assert!((c.transform.get()[1] - 1.0).abs() < 0.00001);
}

#[test]
fn test_scale() {
    let c = Context::new();
    let c = c.scale(2.0, 3.0);
    assert!((c.transform.get()[0] - 2.0).abs() < 0.00001);
    assert!((c.transform.get()[4] - 3.0).abs() < 0.00001);
}
<|endoftext|>


<commit_before>// TODO:
//   - get completion actually working
//   - formatting

extern crate log;
extern crate simplelog;

use std::fs;
use std::env;
use std::hash;
use std::collections;
//use std::error::Error;
use std::io::prelude::*;
use goblin::{Object};
use goblin::pe::{PE};
use log::{trace, debug, info, error};

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments")
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config {
            filename: filename
        })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info,
                                simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
}

fn foo(pe: &PE) -> Result<(), Error> {
    info!("foo: {}", pe.name.unwrap_or("(unknown)"));

    if pe.exports.len() > 0 {
        info!("exports:");
        for export in pe.exports.iter() {
            info!("  - {}", export.name.unwrap_or("(unknown)"));
        }
    }

    // like:
    //     exports:
    //       - advapi32.dll
    //         - OpenProcessToken
    //         ...
    if pe.imports.len() > 0 {
        let dlls: Vec<_> = pe.imports.iter()
                                     .map(|import| {import.dll.to_lowercase()})
                                     .collect::<collections::HashSet<String>>()
                                     .iter()
                                     .map(|e| {e.clone()})
                                     .collect::<Vec<String>>();
        dlls.sort_unstable();

        info!("imports:");
        for dll in dlls.iter() {
            info!("  - {}", dll);

            let mut funcs: Vec<_> = pe.imports.iter()
                                          .filter(|import| { import.dll.to_lowercase() == **dll })
                                          .collect();
            funcs.sort_unstable_by(|a, b| { a.name.cmp(&b.name) });
            for func in funcs {
                info!("    - {}", func.name);
            }
        }
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", args.filename);
        let mut f = match fs::File::open(&args.filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", args.filename);
            return Err(Error::FileFormat);
        }
    }

    let obj = match Object::parse(&buf) {
        Ok(o) => o,
        Err(e) => {
            error!("failed to parse file: {} error: {:?}", args.filename, e);
            return Err(Error::FileFormat);
        }
    };

    match obj {
        Object::PE(pe) => {
            info!("found PE file");
            foo(&pe).expect("failed to foo")
        },
        Object::Elf(_) => {
            error!("found ELF file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Mach(_) => {
            error!("found Mach-O file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Archive(_) => {
            error!("found archive file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Unknown(_) => {
            error!("unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                   buf[0], buf[1],
                   hexdump_ascii(buf[0] as char),
                   hexdump_ascii(buf[1] as char));
            return Err(Error::NotImplemented);
        }
    }

    Ok(())
}

fn hexdump_ascii(c: char) -> char {
    if c.is_ascii() {
        c
    } else {
        '.'
    }
}<commit_msg>pe: read section names<commit_after>// TODO:
//   - get completion actually working
//   - formatting

extern crate log;
extern crate simplelog;

use std::fs;
use std::env;
use std::collections;
use std::io::prelude::*;
use goblin::{Object};
use goblin::pe::{PE};
use log::{trace, debug, info, error};

pub struct Config {
    pub filename: String,
}

impl Config {
    pub fn from_args(args: env::Args) -> Result<Config, &'static str> {
        let args: Vec<String> = args.collect();

        if args.len() < 2 {
            return Err("not enough arguments")
        }

        let filename = args[1].clone();
        trace!("config: parsed filename: {:?}", filename);

        Ok(Config {
            filename: filename
        })
    }
}

pub fn setup_logging(_args: &Config) {
    simplelog::TermLogger::init(simplelog::LevelFilter::Info,
                                simplelog::Config::default())
        .expect("failed to setup logging");
}

#[derive(Debug)]
pub enum Error {
    FileAccess,
    FileFormat,
    NotImplemented,
}

fn foo(pe: &PE, buf: &[u8]) -> Result<(), Error> {
    info!("foo: {}", pe.name.unwrap_or("(unknown)"));

    // like:
    //     exports:
    //       - Foo
    if pe.exports.len() > 0 {
        info!("exports:");
        for export in pe.exports.iter() {
            info!("  - {}", export.name.unwrap_or("(unknown)"));
        }
    }

    // like:
    //     imports:
    //       - advapi32.dll
    //         - OpenProcessToken
    //         ...
    if pe.imports.len() > 0 {
        let mut dlls = pe.imports.iter()
                         .map(|import| {import.dll.to_lowercase()})
                         .collect::<collections::HashSet<String>>()
                         .iter()
                         .map(|e| {e.clone()})
                         .collect::<Vec<String>>();
        dlls.sort_unstable();

        info!("imports:");
        for dll in dlls.iter() {
            info!("  - {}", dll);

            let mut funcs: Vec<_> = pe.imports.iter()
                                          .filter(|import| { import.dll.to_lowercase() == **dll })
                                          .collect();
            funcs.sort_unstable_by(|a, b| { a.name.cmp(&b.name) });

            for func in funcs {
                info!("    - {}", func.name);
            }
        }
    }

    info!("bitness: {}", if pe.is_64 { "64" } else { "32"});
    info!("image base: 0x{:x}", pe.image_base);
    info!("entry rva: 0x{:x}", pe.entry);

    for section in pe.sections.iter() {
        info!("section:");
        if section.real_name.is_some() {
            info!("  name: {} ({})",
                  String::from_utf8_lossy(&section.name[..]),
                  section.real_name.as_ref().unwrap_or(&"(unknown)".to_string())
                  );
        } else {
            info!("  name: {}", String::from_utf8_lossy(&section.name[..]));
        }
    }

    Ok(())
}

pub fn run(args: &Config) -> Result<(), Error> {
    debug!("filename: {:?}", args.filename);

    let mut buf = Vec::new();
    {
        debug!("reading file: {}", args.filename);
        let mut f = match fs::File::open(&args.filename) {
            Ok(f) => f,
            Err(_) => {
                error!("failed to open file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        let bytes_read = match f.read_to_end(&mut buf) {
            Ok(c) => c,
            Err(_) => {
                error!("failed to read entire file: {}", args.filename);
                return Err(Error::FileAccess);
            }
        };
        debug!("read {} bytes", bytes_read);
        if bytes_read < 0x10 {
            error!("file too small: {}", args.filename);
            return Err(Error::FileFormat);
        }
    }

    let obj = match Object::parse(&buf) {
        Ok(o) => o,
        Err(e) => {
            error!("failed to parse file: {} error: {:?}", args.filename, e);
            return Err(Error::FileFormat);
        }
    };

    match obj {
        Object::PE(pe) => {
            info!("found PE file");
            foo(&pe, &buf).expect("failed to foo")
        },
        Object::Elf(_) => {
            error!("found ELF file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Mach(_) => {
            error!("found Mach-O file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Archive(_) => {
            error!("found archive file, format not yet supported");
            return Err(Error::NotImplemented);
        },
        Object::Unknown(_) => {
            error!("unknown file format, magic: | {:02X} {:02X} | '{}{}' ",
                   buf[0], buf[1],
                   hexdump_ascii(buf[0] as char),
                   hexdump_ascii(buf[1] as char));
            return Err(Error::NotImplemented);
        }
    }

    Ok(())
}

fn hexdump_ascii(c: char) -> char {
    if c.is_ascii() {
        c
    } else {
        '.'
    }
}<|endoftext|>


<commit_before>use std::ops::Deref;

/// A `Vec` in sorted order without duplicates.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SortedUniqueVec<T: Ord + Clone> {
    vec: Vec<T>,
}

pub fn is_sorted_unique<T: Ord>(slice: &[T]) -> bool {
    if slice.len() < 2 {
        true
    } else {
        slice.windows(2).all(|win| win[0] < win[1])
    }
}

pub enum LeftOrRight {
    Left,
    Right,
}

impl<T: Ord + Clone> SortedUniqueVec<T> {
    pub fn new() -> Self {
        SortedUniqueVec { vec: Vec::new() }
    }

    /// Panics if sorted order is destroyed by this push operation.
    pub fn push(&mut self, item: T) {
        if let Some(last_item) = self.last() {
            assert!(last_item < &item);
        }
        self.vec.push(item);
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn contains(&self, element: &T) -> bool {
        self.vec.binary_search(element).is_ok()
    }

    /// Insert `element` into the sorted list.
    ///
    /// Panics if an element with the same key (according to the Eq trait) already exists.
    pub fn insert(&mut self, element: T) {
        match self.vec.binary_search(&element) {
            Ok(_idx) => {
                panic!("Element already exists");
            }
            Err(idx) => {
                self.vec.insert(idx, element);
            }
        }
    }

    /// Merges `self` and `other` into a new SortedVec.
    /// `choose_equal` decides which one of two equal values to take.
    pub fn merge<F>(&self, other: &Self, choose_equal: &F) -> Self
        where F: Fn(&T, &T) -> LeftOrRight
    {
        let mut vec = Vec::with_capacity(self.len() + other.len());

        let mut left_iter = self.vec.iter().peekable();
        let mut right_iter = other.vec.iter().peekable();

        enum Take {
            OneLeft,
            OneRight,
            Both,
            AllLeft,
            AllRight,
        };

        loop {
            let take;

            match (left_iter.peek(), right_iter.peek()) {
                (Some(l), Some(r)) => {
                    if l < r {
                        take = Take::OneLeft;
                    } else if r < l {
                        take = Take::OneRight;
                    } else {
                        take = Take::Both;
                    }
                }
                (Some(_), None) => {
                    take = Take::AllLeft;
                }
                (None, Some(_)) => {
                    take = Take::AllRight;
                }
                (None, None) => {
                    break;
                }
            }
            match take {
                Take::OneLeft => {
                    vec.push((*left_iter.next().unwrap()).clone());
                }
                Take::OneRight => {
                    vec.push((*right_iter.next().unwrap()).clone());
                }
                Take::Both => {
                    // two equal values
                    let left_value = left_iter.next().unwrap();
                    let right_value = right_iter.next().unwrap();
                    match choose_equal(left_value, right_value) {
                        LeftOrRight::Left => {
                            vec.push((*left_value).clone());
                        }
                        LeftOrRight::Right => {
                            vec.push((*right_value).clone());
                        }
                    }
                }
                Take::AllLeft => {
                    for item in left_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }
                Take::AllRight => {
                    for item in right_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }

            }
        }

        debug_assert!(is_sorted_unique(&vec));
        SortedUniqueVec { vec: vec }
    }
}

impl<T: Ord + Clone> AsRef<[T]> for SortedUniqueVec<T> {
    fn as_ref(&self) -> &[T] {
        &self.vec
    }
}

impl<T: Ord + Clone> Deref for SortedUniqueVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec
    }
}

#[test]
fn test_insert() {
    let mut s = SortedUniqueVec::new();
    s.insert(5);
    s.insert(1);
    s.insert(8);
    s.insert(0);
    assert!(is_sorted_unique(&s));
    assert_eq!(&[0, 1, 5, 8][..], s.as_ref());
    assert_eq!(4, s.len());
}

#[test]
fn test_merge() {
    let mut s1 = SortedUniqueVec::new();
    s1.insert(5);
    s1.insert(1);
    s1.insert(8);
    s1.insert(0);
    assert!(is_sorted_unique(&s1));

    let mut s2 = SortedUniqueVec::new();
    s2.insert(55);
    s2.insert(1);
    s2.insert(5);
    s2.insert(7);
    s2.insert(9);
    assert!(is_sorted_unique(&s2));

    let r = s1.merge(&s2, &|_, _| LeftOrRight::Left);
    assert!(is_sorted_unique(&r));
    assert_eq!(&[0, 1, 5, 7, 8, 9, 55][..], r.as_ref());
}

#[test]
fn test_push_ok() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(6);
    assert!(is_sorted_unique(&s));
    assert_eq!(3, s.len());
    assert_eq!(&[0, 5, 6][..], s.as_ref());
}

#[test]
#[should_panic]
fn test_push_fail() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(1);
    s.push(1);
}

#[test]
#[should_panic]
fn test_push_fail2() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(9);
    s.push(3);
}
<commit_msg>Add SortedUniqueVec#with_capacity<commit_after>use std::ops::Deref;

/// A `Vec` in sorted order without duplicates.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SortedUniqueVec<T: Ord + Clone> {
    vec: Vec<T>,
}

pub fn is_sorted_unique<T: Ord>(slice: &[T]) -> bool {
    if slice.len() < 2 {
        true
    } else {
        slice.windows(2).all(|win| win[0] < win[1])
    }
}

pub enum LeftOrRight {
    Left,
    Right,
}

impl<T: Ord + Clone> SortedUniqueVec<T> {
    pub fn new() -> Self {
        SortedUniqueVec { vec: Vec::new() }
    }

    pub fn with_capacity(capa: usize) -> Self {
        SortedUniqueVec { vec: Vec::with_capacity(capa) }
    }

    /// Panics if sorted order is destroyed by this push operation.
    pub fn push(&mut self, item: T) {
        if let Some(last_item) = self.last() {
            assert!(last_item < &item);
        }
        self.vec.push(item);
    }

    pub fn len(&self) -> usize {
        self.vec.len()
    }

    pub fn contains(&self, element: &T) -> bool {
        self.vec.binary_search(element).is_ok()
    }

    /// Insert `element` into the sorted list.
    ///
    /// Panics if an element with the same key (according to the Eq trait) already exists.
    pub fn insert(&mut self, element: T) {
        match self.vec.binary_search(&element) {
            Ok(_idx) => {
                panic!("Element already exists");
            }
            Err(idx) => {
                self.vec.insert(idx, element);
            }
        }
    }

    /// Merges `self` and `other` into a new SortedVec.
    /// `choose_equal` decides which one of two equal values to take.
    pub fn merge<F>(&self, other: &Self, choose_equal: &F) -> Self
        where F: Fn(&T, &T) -> LeftOrRight
    {
        let mut vec = Vec::with_capacity(self.len() + other.len());

        let mut left_iter = self.vec.iter().peekable();
        let mut right_iter = other.vec.iter().peekable();

        enum Take {
            OneLeft,
            OneRight,
            Both,
            AllLeft,
            AllRight,
        };

        loop {
            let take;

            match (left_iter.peek(), right_iter.peek()) {
                (Some(l), Some(r)) => {
                    if l < r {
                        take = Take::OneLeft;
                    } else if r < l {
                        take = Take::OneRight;
                    } else {
                        take = Take::Both;
                    }
                }
                (Some(_), None) => {
                    take = Take::AllLeft;
                }
                (None, Some(_)) => {
                    take = Take::AllRight;
                }
                (None, None) => {
                    break;
                }
            }
            match take {
                Take::OneLeft => {
                    vec.push((*left_iter.next().unwrap()).clone());
                }
                Take::OneRight => {
                    vec.push((*right_iter.next().unwrap()).clone());
                }
                Take::Both => {
                    // two equal values
                    let left_value = left_iter.next().unwrap();
                    let right_value = right_iter.next().unwrap();
                    match choose_equal(left_value, right_value) {
                        LeftOrRight::Left => {
                            vec.push((*left_value).clone());
                        }
                        LeftOrRight::Right => {
                            vec.push((*right_value).clone());
                        }
                    }
                }
                Take::AllLeft => {
                    for item in left_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }
                Take::AllRight => {
                    for item in right_iter {
                        vec.push((*item).clone());
                    }
                    break;
                }

            }
        }

        debug_assert!(is_sorted_unique(&vec));
        SortedUniqueVec { vec: vec }
    }
}

impl<T: Ord + Clone> AsRef<[T]> for SortedUniqueVec<T> {
    fn as_ref(&self) -> &[T] {
        &self.vec
    }
}

impl<T: Ord + Clone> Deref for SortedUniqueVec<T> {
    type Target = [T];

    fn deref(&self) -> &[T] {
        &self.vec
    }
}

#[test]
fn test_insert() {
    let mut s = SortedUniqueVec::new();
    s.insert(5);
    s.insert(1);
    s.insert(8);
    s.insert(0);
    assert!(is_sorted_unique(&s));
    assert_eq!(&[0, 1, 5, 8][..], s.as_ref());
    assert_eq!(4, s.len());
}

#[test]
fn test_merge() {
    let mut s1 = SortedUniqueVec::new();
    s1.insert(5);
    s1.insert(1);
    s1.insert(8);
    s1.insert(0);
    assert!(is_sorted_unique(&s1));

    let mut s2 = SortedUniqueVec::new();
    s2.insert(55);
    s2.insert(1);
    s2.insert(5);
    s2.insert(7);
    s2.insert(9);
    assert!(is_sorted_unique(&s2));

    let r = s1.merge(&s2, &|_, _| LeftOrRight::Left);
    assert!(is_sorted_unique(&r));
    assert_eq!(&[0, 1, 5, 7, 8, 9, 55][..], r.as_ref());
}

#[test]
fn test_push_ok() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(6);
    assert!(is_sorted_unique(&s));
    assert_eq!(3, s.len());
    assert_eq!(&[0, 5, 6][..], s.as_ref());
}

#[test]
#[should_panic]
fn test_push_fail() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(1);
    s.push(1);
}

#[test]
#[should_panic]
fn test_push_fail2() {
    let mut s = SortedUniqueVec::new();
    s.push(0);
    s.push(5);
    s.push(9);
    s.push(3);
}
<|endoftext|>