<commit_before>extern crate sodiumoxide;

use std::collections::HashMap;
use std::vec;
use sodiumoxide::crypto::hash::sha512;
use sodiumoxide::crypto::sign::ed25519::{
    self, PublicKey, SecretKey, PUBLICKEYBYTES, SECRETKEYBYTES};
use protobuf::Message;
use simples_pb;

pub fn slice_to_pk(bytes: &[u8]) -> Option<PublicKey> {
    if bytes.len() != PUBLICKEYBYTES { return None; }
    let mut key:[u8; PUBLICKEYBYTES] = [0; PUBLICKEYBYTES];
    for i in range(0, PUBLICKEYBYTES) {
        key[i] = bytes[i];
    }
    Some(PublicKey(key))
}

pub fn slice_to_sk(bytes: &[u8]) -> Option<SecretKey> {
    if bytes.len() != SECRETKEYBYTES { return None; }
    let mut key:[u8; SECRETKEYBYTES] = [0; SECRETKEYBYTES];
    for i in range(0, SECRETKEYBYTES) {
        key[i] = bytes[i];
    }
    Some(SecretKey(key))
}

fn hash_message<M: Message>(obj: &M) -> Vec<u8> {
    let bytes = &obj.write_to_bytes().unwrap()[];
    let sha512::Digest(commit_hash) = sha512::hash(&bytes[]);
    vec::as_vec(&commit_hash[]).clone()
}

pub trait Transaction {
    fn check_signatures(&self) -> Result<(), &'static str>;
}

impl Transaction for simples_pb::Transaction {
    fn check_signatures(&self) -> Result<(), &'static str> {
        let commit_hash = hash_message(self.get_commit());
        if commit_hash[] != self.get_commit_hash()[] {
            return Err("Invalid hash.");
        }
        let mut sign_map = HashMap::<&[u8], &[u8]>::new();
        for sign in self.get_signatures().iter() {
            sign_map.insert(sign.get_public_key(), sign.get_payload());
        }
        for transfer in self.get_commit().get_transfers().iter() {
            match sign_map.get(transfer.get_source_pk()) {
                Some(signature) => {
                    let pk = slice_to_pk(transfer.get_source_pk()).unwrap();
                    match ed25519::verify(&signature[], &pk) {
                        Some(hash) => {
                            if commit_hash[] != hash[] {
                                return Err("The incorrect hash is signed.")
                            }
                        },
                        None => return Err("Invalid signature.")
                    }
                },
                None => return Err("Missing key.")
            }
        }
        Ok(())
    }
}

#[derive(Default)]
pub struct TransactionBuilder {
    transfer_secret_keys: Vec<SecretKey>,
    bounty_secret_key: Option<SecretKey>,
    commit: simples_pb::Commitment
}

impl TransactionBuilder {
    pub fn new() -> TransactionBuilder {
        TransactionBuilder {
            transfer_secret_keys: Vec::<SecretKey>::new(),
            bounty_secret_key: None,
            commit: simples_pb::Commitment::new()
        }
    }

    pub fn add_transfer(
        mut self, sk: &SecretKey, source: &PublicKey, destination: &PublicKey,
        tokens: u64, op_index:u32) -> TransactionBuilder {
        let mut transfer = simples_pb::Transfer::new();
        transfer.set_op_index(op_index);
        transfer.set_tokens(tokens);
        transfer.mut_source_pk().push_all(&source.0);
        transfer.mut_destination_pk().push_all(&destination.0);

        self.transfer_secret_keys.push(sk.clone());
        self.commit.mut_transfers().push(transfer);
        self
    }

    pub fn set_bounty(mut self, sk: &SecretKey, source: &PublicKey,
                      bounty: u64) -> TransactionBuilder {
        self.bounty_secret_key = Some(sk.clone());
        self.commit.mut_bounty_pk().push_all(&source.0);
        self.commit.set_bounty(bounty);
        self
    }

    pub fn build(self) -> Result<simples_pb::Transaction, &'static str> {
        let commit_hash = hash_message(&self.commit);
        let mut transaction = simples_pb::Transaction::new();
        {
            let mut signatures = transaction.mut_signatures();
            let mut transfers_and_skeys = self.commit.get_transfers().iter()
                .zip(self.transfer_secret_keys.iter());

            for (transfer, sk) in transfers_and_skeys {
                let signature: Vec<u8> = ed25519::sign(&commit_hash[], sk);
                let pk_bytes = vec::as_vec(transfer.get_source_pk()).clone();
                let pk = slice_to_pk(&pk_bytes[]).unwrap();
                match ed25519::verify(&signature[0..], &pk) {
                    Some(_) => {
                        let mut sign = simples_pb::DetachedSignature::new();
                        sign.set_public_key(pk_bytes);
                        sign.set_payload(signature);
                        signatures.push(sign);
                    },
                    None => return Err("Invalid key for source account.")
                }
            }
        }
        transaction.set_commit(self.commit);
        transaction.set_commit_hash(commit_hash.clone());
        match transaction.check_signatures() {
            Ok(_) => Ok(transaction),
            Err(msg) => Err(msg)
        }
    }
}
<commit_msg>Use detached signatures and take self as &mut.<commit_after>extern crate sodiumoxide;

use std::collections::HashMap;
use std::vec;

use sodiumoxide::crypto::hash::sha512;
use sodiumoxide::crypto::sign::ed25519::{
    self, PublicKey, SecretKey, PUBLICKEYBYTES, SECRETKEYBYTES,
    Signature, SIGNATUREBYTES, sign_detached, verify_detached};
use protobuf::Message;

use simples_pb;

pub fn slice_to_pk(bytes: &[u8]) -> Option<PublicKey> {
    if bytes.len() != PUBLICKEYBYTES { return None; }
    let mut key:[u8; PUBLICKEYBYTES] = [0; PUBLICKEYBYTES];
    for i in range(0, PUBLICKEYBYTES) {
        key[i] = bytes[i];
    }
    Some(PublicKey(key))
}

pub fn slice_to_sk(bytes: &[u8]) -> Option<SecretKey> {
    if bytes.len() != SECRETKEYBYTES { return None; }
    let mut key:[u8; SECRETKEYBYTES] = [0; SECRETKEYBYTES];
    for i in range(0, SECRETKEYBYTES) {
        key[i] = bytes[i];
    }
    Some(SecretKey(key))
}

pub fn slice_to_signature(bytes: &[u8]) -> Option<Signature> {
    if bytes.len() != SIGNATUREBYTES { return None; }
    let mut sign:[u8; SIGNATUREBYTES] = [0; SIGNATUREBYTES];
    for i in range(0, SIGNATUREBYTES) {
        sign[i] = bytes[i];
    }
    Some(Signature(sign))
}

fn hash_message<M: Message>(obj: &M) -> Vec<u8> {
    let bytes = &obj.write_to_bytes().unwrap()[];
    let sha512::Digest(commit_hash) = sha512::hash(&bytes[]);
    vec::as_vec(&commit_hash[]).clone()
}

pub trait Transaction {
    fn check_signatures(&self) -> Result<(), &'static str>;
}

impl Transaction for simples_pb::Transaction {
    fn check_signatures(&self) -> Result<(), &'static str> {
        let commit_bytes = &self.get_commit().write_to_bytes().unwrap()[];
        let mut sign_map = HashMap::<&[u8], &[u8]>::new();
        for sign in self.get_signatures().iter() {
            sign_map.insert(sign.get_public_key(), sign.get_payload());
        }
        for transfer in self.get_commit().get_transfers().iter() {
            match sign_map.get(transfer.get_source_pk()) {
                Some(sign_bytes) => {
                    let pk = slice_to_pk(transfer.get_source_pk()).unwrap();
                    let signature = slice_to_signature(&sign_bytes[]).unwrap();
                    if !verify_detached(&signature, commit_bytes, &pk) {
                        return Err("Invalid signature.")
                    }
                },
                None => return Err("Missing key.")
            }
        }
        Ok(())
    }
}

#[derive(Default)]
pub struct TransactionBuilder {
    transfer_secret_keys: Vec<SecretKey>,
    bounty_secret_key: Option<SecretKey>,
    commit: simples_pb::Commitment
}

impl TransactionBuilder {
    pub fn new() -> TransactionBuilder {
        TransactionBuilder {
            transfer_secret_keys: Vec::<SecretKey>::new(),
            bounty_secret_key: None,
            commit: simples_pb::Commitment::new()
        }
    }

    pub fn add_transfer(
        &mut self, sk: &SecretKey, source: &PublicKey, destination: &PublicKey,
        tokens: u64, op_index:u32) -> &mut Self {
        let mut transfer = simples_pb::Transfer::new();
        transfer.set_op_index(op_index);
        transfer.set_tokens(tokens);
        transfer.mut_source_pk().push_all(&source.0);
        transfer.mut_destination_pk().push_all(&destination.0);

        self.transfer_secret_keys.push(sk.clone());
        self.commit.mut_transfers().push(transfer);
        self
    }

    pub fn set_bounty(&mut self, sk: &SecretKey, source: &PublicKey,
                      bounty: u64) -> &mut Self {
        self.bounty_secret_key = Some(sk.clone());
        self.commit.mut_bounty_pk().push_all(&source.0);
        self.commit.set_bounty(bounty);
        self
    }

    pub fn build(self) -> Result<simples_pb::Transaction, &'static str> {
        let mut transaction = simples_pb::Transaction::new();
        let commit_bytes = &self.commit.write_to_bytes().unwrap()[];
        for (transfer, sk) in self.commit.get_transfers().iter()
            .zip(self.transfer_secret_keys.iter())
        {
            let signature = sign_detached(commit_bytes, sk);
            let pk_bytes = vec::as_vec(transfer.get_source_pk()).clone();
            let pk = slice_to_pk(&pk_bytes[]).unwrap();
            match verify_detached(&signature, commit_bytes, &pk) {
                true => {
                    let mut sign = simples_pb::DetachedSignature::new();
                    sign.set_public_key(pk_bytes);
                    sign.set_payload(signature.0.to_vec());
                    transaction.mut_signatures().push(sign);
                },
                false => return Err("Invalid key for source account.")
            }
        }
        transaction.set_commit(self.commit);
        try!(transaction.check_signatures());
        Ok(transaction)
    }
}
<|endoftext|>


<commit_before>//! Virtual machine.

use std::rc::Rc;
use std::{error, result};
use std::fmt;
use std::collections::HashMap;
use std::error::Error as StdError;
use num::integer::Integer;
use num::{zero, one};
use item::{Block, BlockItem, Stack, StackItem};

pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Error {
    TypeError,
    DivideByZero,
    StackUnderflow,
    UnknownMethod(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::UnknownMethod(ref s) => write!(f, "{}: {}", self.description(), s),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::DivideByZero => "Divided by zero",
            Error::TypeError => "Type error",
            Error::StackUnderflow => "Stack underflow",
            Error::UnknownMethod(_) => "Unknown method",
        }
    }
}

pub enum Method<I> {
    Builtin(Box<Fn(&mut Vm<I>) -> Result<()>>),
    Block(Block<I>),
}

pub struct Vm<I> {
    pub stack: Stack<I>,
    pub methods: HashMap<String, Rc<Method<I>>>,
}

impl<I> Vm<I> where I: Integer + Clone {
    pub fn run(&mut self, item: &BlockItem<I>) -> Result<()> {
        match *item {
            BlockItem::Literal(ref stack_item) =>
                self.stack.push(stack_item.clone()),
            BlockItem::Call(ref name) => {
                let method = match self.methods.get(&*name) {
                    Some(m) => m.clone(),
                    None => return Err(Error::UnknownMethod(name.clone())),
                };
                try!(match *method {
                    Method::Builtin(ref f) => (**f)(self),
                    Method::Block(ref b) => self.run_block(b),
                })
            },
        }
        Ok(())
    }

    pub fn run_block(&mut self, block: &Block<I>) -> Result<()> {
        for item in block.iter() {
            try!(self.run(item));
        }
        Ok(())
    }

    pub fn builtin<S>(&mut self, name: S, method: Box<Fn(&mut Vm<I>)
                   -> Result<()>>) where S: Into<String> {
        self.methods.insert(name.into(), Rc::new(Method::Builtin(method)));
    }

    pub fn pop_integer(&mut self) -> Result<I> {
        match self.stack.pop() {
            Some(StackItem::Integer(i)) => Ok(i),
            Some(..) => Err(Error::TypeError),
            None => Err(Error::StackUnderflow),
        }
    }

    pub fn new() -> Vm<I> {
        Vm {
            stack: Vec::new(),
            methods: HashMap::new(),
        }
    }

    pub fn new_with_builtins() -> Vm<I> {
        let mut vm = Vm::<I>::new();
        vm.builtin("+", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 + n2));
            Ok(())
        }));
        vm.builtin("-", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 - n2));
            Ok(())
        }));
        vm.builtin("*", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 * n2));
            Ok(())
        }));
        vm.builtin("/", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            if n2 == zero() {
                return Err(Error::DivideByZero);
            }
            vm.stack.push(StackItem::Integer(n1 / n2));
            Ok(())
        }));
        vm.builtin("fn", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let name = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            match (name, block) {
                (StackItem::Symbol(s), StackItem::Block(b)) =>
                    { vm.methods.insert(s, Rc::new(Method::Block(b))); },
                _ => return Err(Error::TypeError),
            }
            Ok(())
        }));
        vm.builtin("swap", Box::new(|vm| {
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(b);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("over", Box::new(|vm| {
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(a.clone());
            vm.stack.push(b);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("rot", Box::new(|vm| {
            let c = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(b);
            vm.stack.push(c);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("dup", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(a.clone());
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("pop", Box::new(|vm| {
            let _ = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            Ok(())
        }));
        vm.builtin("false", Box::new(|vm| {
            vm.stack.push(StackItem::Boolean(false));
            Ok(())
        }));
        vm.builtin("true", Box::new(|vm| {
            vm.stack.push(StackItem::Boolean(true));
            Ok(())
        }));
        vm.builtin("eq", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(StackItem::Boolean(a == b));
            Ok(())
        }));
        vm.builtin("not", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let StackItem::Boolean(boolean) = a {
                vm.stack.push(StackItem::Boolean(!boolean));
            } else {
                return Err(Error::TypeError)
            }
            Ok(())
        }));
        vm.builtin("if", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let condition = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(block), StackItem::Boolean(condition)) =
                    (block, condition) {
                if condition {
                    try!(vm.run_block(&block));
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("while", Box::new(|vm| {
            let action_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let condition_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(action_block), StackItem::Block(condition_block)) =
                    (action_block, condition_block) {
                loop {
                    try!(vm.run_block(&condition_block));
                    let condition = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
                    if let StackItem::Boolean(condition) = condition {
                        if condition {
                            try!(vm.run_block(&action_block));
                        } else {
                            break;
                        }
                    } else {
                        return Err(Error::TypeError);
                    }
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("times", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let times = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(block), StackItem::Integer(mut times)) =
                    (block, times) {
                while times > zero() {
                    try!(vm.run_block(&block));
                    times = times - one::<I>();
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm
    }
}

impl<I> fmt::Display for Vm<I> where I: fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for item in &self.stack {
            try!(write!(f, "{} ", item));
        }
        Ok(())
    }
}
<commit_msg>Add more builtins<commit_after>//! Virtual machine.

use std::rc::Rc;
use std::{error, result};
use std::fmt;
use std::collections::HashMap;
use std::error::Error as StdError;
use num::integer::Integer;
use num::{zero, one};
use item::{Block, BlockItem, Stack, StackItem};

pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Error {
    TypeError,
    DivideByZero,
    StackUnderflow,
    UnknownMethod(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::UnknownMethod(ref s) => write!(f, "{}: {}", self.description(), s),
            _ => write!(f, "{}", self.description()),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::DivideByZero => "Divided by zero",
            Error::TypeError => "Type error",
            Error::StackUnderflow => "Stack underflow",
            Error::UnknownMethod(_) => "Unknown method",
        }
    }
}

pub enum Method<I> {
    Builtin(Box<Fn(&mut Vm<I>) -> Result<()>>),
    Block(Block<I>),
}

pub struct Vm<I> {
    pub stack: Stack<I>,
    pub methods: HashMap<String, Rc<Method<I>>>,
}

impl<I> Vm<I> where I: Integer + Clone {
    pub fn run(&mut self, item: &BlockItem<I>) -> Result<()> {
        match *item {
            BlockItem::Literal(ref stack_item) =>
                self.stack.push(stack_item.clone()),
            BlockItem::Call(ref name) => {
                let method = match self.methods.get(&*name) {
                    Some(m) => m.clone(),
                    None => return Err(Error::UnknownMethod(name.clone())),
                };
                try!(match *method {
                    Method::Builtin(ref f) => (**f)(self),
                    Method::Block(ref b) => self.run_block(b),
                })
            },
        }
        Ok(())
    }

    pub fn run_block(&mut self, block: &Block<I>) -> Result<()> {
        for item in block.iter() {
            try!(self.run(item));
        }
        Ok(())
    }

    pub fn builtin<S>(&mut self, name: S, method: Box<Fn(&mut Vm<I>)
                   -> Result<()>>) where S: Into<String> {
        self.methods.insert(name.into(), Rc::new(Method::Builtin(method)));
    }

    pub fn pop_integer(&mut self) -> Result<I> {
        match self.stack.pop() {
            Some(StackItem::Integer(i)) => Ok(i),
            Some(..) => Err(Error::TypeError),
            None => Err(Error::StackUnderflow),
        }
    }

    pub fn new() -> Vm<I> {
        Vm {
            stack: Vec::new(),
            methods: HashMap::new(),
        }
    }

    pub fn new_with_builtins() -> Vm<I> {
        let mut vm = Vm::<I>::new();
        vm.builtin("+", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 + n2));
            Ok(())
        }));
        vm.builtin("-", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 - n2));
            Ok(())
        }));
        vm.builtin("*", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            vm.stack.push(StackItem::Integer(n1 * n2));
            Ok(())
        }));
        vm.builtin("/", Box::new(|vm| {
            let n2 = try!(vm.pop_integer());
            let n1 = try!(vm.pop_integer());
            if n2 == zero() {
                return Err(Error::DivideByZero);
            }
            vm.stack.push(StackItem::Integer(n1 / n2));
            Ok(())
        }));
        vm.builtin("fn", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let name = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            match (name, block) {
                (StackItem::Symbol(s), StackItem::Block(b)) =>
                    { vm.methods.insert(s, Rc::new(Method::Block(b))); },
                _ => return Err(Error::TypeError),
            }
            Ok(())
        }));
        vm.builtin("swap", Box::new(|vm| {
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(b);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("over", Box::new(|vm| {
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(a.clone());
            vm.stack.push(b);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("rot", Box::new(|vm| {
            let c = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(b);
            vm.stack.push(c);
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("dup", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(a.clone());
            vm.stack.push(a);
            Ok(())
        }));
        vm.builtin("pop", Box::new(|vm| {
            let _ = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            Ok(())
        }));
        vm.builtin("false", Box::new(|vm| {
            vm.stack.push(StackItem::Boolean(false));
            Ok(())
        }));
        vm.builtin("true", Box::new(|vm| {
            vm.stack.push(StackItem::Boolean(true));
            Ok(())
        }));
        vm.builtin("eq", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            vm.stack.push(StackItem::Boolean(a == b));
            Ok(())
        }));
        vm.builtin("not", Box::new(|vm| {
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let StackItem::Boolean(boolean) = a {
                vm.stack.push(StackItem::Boolean(!boolean));
            } else {
                return Err(Error::TypeError)
            }
            Ok(())
        }));
        vm.builtin("if", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let condition = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(block), StackItem::Boolean(condition)) =
                    (block, condition) {
                if condition {
                    try!(vm.run_block(&block));
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("ifelse", Box::new(|vm| {
            let else_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let if_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let condition = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(else_block), StackItem::Block(if_block), StackItem::Boolean(condition)) =
                    (else_block, if_block, condition) {
                if condition {
                    try!(vm.run_block(&if_block));
                } else {
                    try!(vm.run_block(&else_block));
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("or", Box::new(|vm| {
            let b = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let a = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Boolean(a), StackItem::Boolean(b)) =
                    (a, b) {
                vm.stack.push(StackItem::Boolean(a || b));
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("while", Box::new(|vm| {
            let action_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let condition_block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(action_block), StackItem::Block(condition_block)) =
                    (action_block, condition_block) {
                loop {
                    try!(vm.run_block(&condition_block));
                    let condition = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
                    if let StackItem::Boolean(condition) = condition {
                        if condition {
                            try!(vm.run_block(&action_block));
                        } else {
                            break;
                        }
                    } else {
                        return Err(Error::TypeError);
                    }
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm.builtin("times", Box::new(|vm| {
            let block = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            let times = try!(vm.stack.pop().ok_or(Error::StackUnderflow));
            if let (StackItem::Block(block), StackItem::Integer(mut times)) =
                    (block, times) {
                while times > zero() {
                    try!(vm.run_block(&block));
                    times = times - one::<I>();
                }
            } else {
                return Err(Error::TypeError);
            }
            Ok(())
        }));
        vm
    }
}

impl<I> fmt::Display for Vm<I> where I: fmt::Display {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for item in &self.stack {
            try!(write!(f, "{} ", item));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer]);
    }

    pub fn input(&self) {
        let mut buffer = [0; 1];
        let mut stdin = io::stdin();
        stdin.read_exact(&mut buffer).unwrap();
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }
}
<commit_msg>Add vm.apply_many function<commit_after>use std::io;
use std::io::Read;
use command::Command;

type Cell = u8;

pub struct VM {
    cells: [Cell; 30_000],
    data_pointer: usize,
}

impl VM {
    pub fn new() -> VM {
        VM { cells: [0; 30_000], data_pointer: 0 }
    }

    pub fn output(&self) {
        print!("{}", self.cells[self.data_pointer]);
    }

    pub fn input(&self) {
        let mut buffer = [0; 1];
        let mut stdin = io::stdin();
        stdin.read_exact(&mut buffer).unwrap();
    }

    pub fn increment(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] + 1;
    }

    pub fn decrement(&mut self) {
        self.cells[self.data_pointer] = self.cells[self.data_pointer] - 1;
    }

    pub fn right_shift(&mut self) {
        self.data_pointer = self.data_pointer + 1;
    }

    pub fn left_shift(&mut self) {
        self.data_pointer = self.data_pointer - 1;
    }

    pub fn apply(&mut self, command: &Command) {
        match command {
            &Command::Output => self.output(),
            &Command::Input => self.input(),
            &Command::Increment => self.increment(),
            &Command::Decrement => self.decrement(),
            &Command::RightShift => self.right_shift(),
            &Command::LeftShift => self.left_shift(),
        }
    }

    pub fn apply_many(&mut self, commands: &[Command]) {
        for command in commands {
            self.apply(&command)
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate toml;

#[derive(Debug, Deserialize, PartialEq)]
enum TheEnum {
    Plain,
    Tuple(i64, bool),
    NewType(String),
    Struct { value: i64 },
}

#[derive(Debug, Deserialize, PartialEq)]
struct Val {
    val: TheEnum,
}

#[derive(Debug, Deserialize, PartialEq)]
struct Multi {
    enums: Vec<TheEnum>,
}

mod enum_unit {
    use super::*;

    #[test]
    fn from_str() {
        assert_eq!(TheEnum::Plain, toml::from_str("\"Plain\"").unwrap());
    }

    #[test]
    fn from_inline_table() {
        assert_eq!(TheEnum::Plain, toml::from_str("{ Plain = {} }").unwrap());
        assert_eq!(
            Val {
                val: TheEnum::Plain
            },
            toml::from_str("val = { Plain = {} }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap());
    }
}

mod enum_tuple {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::Tuple(-123, true),
            toml::from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::Tuple(-123, true)
            },
            toml::from_str("val = { Tuple = { 0 = -123, 1 = true } }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(
            TheEnum::Tuple(-123, true),
            toml::from_str(
                r#"[Tuple]
                0 = -123
                1 = true
                "#
            )
            .unwrap()
        );
    }
}

mod enum_newtype {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::NewType("value".to_string()),
            toml::from_str(r#"{ NewType = "value" }"#).unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::NewType("value".to_string()),
            },
            toml::from_str(r#"val = { NewType = "value" }"#).unwrap()
        );
    }
}

mod enum_struct {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::Struct { value: -123 },
            toml::from_str("{ Struct = { value = -123 } }").unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::Struct { value: -123 }
            },
            toml::from_str("val = { Struct = { value = -123 } }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(
            TheEnum::Struct { value: -123 },
            toml::from_str(
                r#"[Struct]
                value = -123
                "#
            )
            .unwrap()
        );
    }
}

mod enum_array {
    use super::*;

    #[test]
    fn from_inline_tables() {
        let toml_str = r#"
            enums = [
                { Plain = {} },
                { Tuple = { 0 = -123, 1 = true } },
                { NewType = "value" },
                { Struct = { value = -123 } }
            ]"#;
        assert_eq!(
            Multi {
                enums: vec![
                    TheEnum::Plain,
                    TheEnum::Tuple(-123, true),
                    TheEnum::NewType("value".to_string()),
                    TheEnum::Struct { value: -123 },
                ]
            },
            toml::from_str(toml_str).unwrap()
        );
    }
}
<commit_msg>Added ignored tests for deserializing enums from dotted table.<commit_after>#[macro_use]
extern crate serde_derive;
extern crate toml;

#[derive(Debug, Deserialize, PartialEq)]
enum TheEnum {
    Plain,
    Tuple(i64, bool),
    NewType(String),
    Struct { value: i64 },
}

#[derive(Debug, Deserialize, PartialEq)]
struct Val {
    val: TheEnum,
}

#[derive(Debug, Deserialize, PartialEq)]
struct Multi {
    enums: Vec<TheEnum>,
}

mod enum_unit {
    use super::*;

    #[test]
    fn from_str() {
        assert_eq!(TheEnum::Plain, toml::from_str("\"Plain\"").unwrap());
    }

    #[test]
    fn from_inline_table() {
        assert_eq!(TheEnum::Plain, toml::from_str("{ Plain = {} }").unwrap());
        assert_eq!(
            Val {
                val: TheEnum::Plain
            },
            toml::from_str("val = { Plain = {} }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap());
    }
}

mod enum_tuple {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::Tuple(-123, true),
            toml::from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::Tuple(-123, true)
            },
            toml::from_str("val = { Tuple = { 0 = -123, 1 = true } }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(
            TheEnum::Tuple(-123, true),
            toml::from_str(
                r#"[Tuple]
                0 = -123
                1 = true
                "#
            )
            .unwrap()
        );
    }
}

mod enum_newtype {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::NewType("value".to_string()),
            toml::from_str(r#"{ NewType = "value" }"#).unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::NewType("value".to_string()),
            },
            toml::from_str(r#"val = { NewType = "value" }"#).unwrap()
        );
    }

    #[test]
    #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"]
    fn from_dotted_table() {
        assert_eq!(
            TheEnum::NewType("value".to_string()),
            toml::from_str(r#"NewType = "value""#).unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::NewType("value".to_string()),
            },
            toml::from_str(
                r#"[val]
                NewType = "value"
                "#
            )
            .unwrap()
        );
    }
}

mod enum_struct {
    use super::*;

    #[test]
    fn from_inline_table() {
        assert_eq!(
            TheEnum::Struct { value: -123 },
            toml::from_str("{ Struct = { value = -123 } }").unwrap()
        );
        assert_eq!(
            Val {
                val: TheEnum::Struct { value: -123 }
            },
            toml::from_str("val = { Struct = { value = -123 } }").unwrap()
        );
    }

    #[test]
    fn from_dotted_table() {
        assert_eq!(
            TheEnum::Struct { value: -123 },
            toml::from_str(
                r#"[Struct]
                value = -123
                "#
            )
            .unwrap()
        );
    }
}

mod enum_array {
    use super::*;

    #[test]
    fn from_inline_tables() {
        let toml_str = r#"
            enums = [
                { Plain = {} },
                { Tuple = { 0 = -123, 1 = true } },
                { NewType = "value" },
                { Struct = { value = -123 } }
            ]"#;
        assert_eq!(
            Multi {
                enums: vec![
                    TheEnum::Plain,
                    TheEnum::Tuple(-123, true),
                    TheEnum::NewType("value".to_string()),
                    TheEnum::Struct { value: -123 },
                ]
            },
            toml::from_str(toml_str).unwrap()
        );
    }

    #[test]
    #[ignore = "Unimplemented: https://github.com/alexcrichton/toml-rs/pull/264#issuecomment-431707209"]
    fn from_dotted_table() {
        let toml_str = r#"[[enums]]
            Plain = {}

            [[enums]]
            Tuple = { 0 = -123, 1 = true }

            [[enums]]
            NewType = "value"

            [[enums]]
            Struct = { value = -123 }
            "#;
        assert_eq!(
            Multi {
                enums: vec![
                    TheEnum::Plain,
                    TheEnum::Tuple(-123, true),
                    TheEnum::NewType("value".to_string()),
                    TheEnum::Struct { value: -123 },
                ]
            },
            toml::from_str(toml_str).unwrap()
        );
    }
}
<|endoftext|>


<commit_before>use askama::Template;

#[derive(Template)]
#[template(path = "base.html")]
struct BaseTemplate<'a> {
    title: &'a str,
}

#[derive(Template)]
#[template(path = "child.html")]
struct ChildTemplate<'a> {
    _parent: BaseTemplate<'a>,
}

#[test]
fn test_use_base_directly() {
    let t = BaseTemplate { title: "Foo" };
    assert_eq!(t.render().unwrap(), "Foo\n\nFoo\nCopyright 2017");
}

#[test]
fn test_simple_extends() {
    let t = ChildTemplate {
        _parent: BaseTemplate { title: "Bar" },
    };
    assert_eq!(
        t.render().unwrap(),
        "Bar\n(Bar) Content goes here\nFoo\nCopyright 2017"
    );
}

#[derive(Template)]
#[template(source = "{% extends \"base.html\" %}", ext = "html")]
struct EmptyChild<'a> {
    title: &'a str,
}

#[test]
fn test_empty_child() {
    let t = EmptyChild { title: "baz" };
    assert_eq!(t.render().unwrap(), "baz\n\nFoo\nCopyright 2017");
}

pub mod parent {
    use askama::Template;
    #[derive(Template)]
    #[template(path = "base.html")]
    pub struct BaseTemplate<'a> {
        pub title: &'a str,
    }
}

pub mod child {
    use super::parent::*;
    use askama::Template;
    #[derive(Template)]
    #[template(path = "child.html")]
    pub struct ChildTemplate<'a> {
        pub _parent: BaseTemplate<'a>,
    }
}

#[test]
fn test_different_module() {
    let t = child::ChildTemplate {
        _parent: parent::BaseTemplate { title: "a" },
    };
    assert_eq!(
        t.render().unwrap(),
        "a\n(a) Content goes here\nFoo\nCopyright 2017"
    );
}

#[derive(Template)]
#[template(path = "nested-base.html")]
struct NestedBaseTemplate {}

#[derive(Template)]
#[template(path = "nested-child.html")]
struct NestedChildTemplate {
    _parent: NestedBaseTemplate,
}

#[test]
fn test_nested_blocks() {
    let t = NestedChildTemplate {
        _parent: NestedBaseTemplate {},
    };
    assert_eq!(t.render().unwrap(), "\ndurpy\n");
}

#[derive(Template)]
#[template(path = "deep-base.html")]
struct DeepBaseTemplate {
    year: u16,
}

#[derive(Template)]
#[template(path = "deep-mid.html")]
struct DeepMidTemplate {
    _parent: DeepBaseTemplate,
    title: String,
}

#[derive(Template)]
#[template(path = "deep-kid.html")]
struct DeepKidTemplate {
    _parent: DeepMidTemplate,
    item: String,
}

#[test]
fn test_deep() {
    let t = DeepKidTemplate {
        _parent: DeepMidTemplate {
            _parent: DeepBaseTemplate { year: 2018 },
            title: "Test".into(),
        },
        item: "Foo".into(),
    };

    assert_eq!(
        t.render().unwrap(),
        "

  Foo Foo Foo

      nav nav nav

"
    );
    assert_eq!(
        t._parent.render().unwrap(),
        "

  Test

      No content found

      nav nav nav

"
    );
    assert_eq!(
        t._parent._parent.render().unwrap(),
        "

    nav nav nav
    Copyright 2018

"
    );
}

#[derive(Template)]
#[template(path = "deep-base.html")]
struct FlatDeepBaseTemplate {
    year: u16,
}

#[derive(Template)]
#[template(path = "deep-mid.html")]
struct FlatDeepMidTemplate {
    title: String,
}

#[derive(Template)]
#[template(path = "deep-kid.html")]
struct FlatDeepKidTemplate {
    item: String,
}

#[test]
fn test_flat_deep() {
    let t = FlatDeepKidTemplate { item: "Foo".into() };

    assert_eq!(
        t.render().unwrap(),
        "

  Foo Foo Foo

      nav nav nav

"
    );

    let t = FlatDeepMidTemplate {
        title: "Test".into(),
    };
    assert_eq!(
        t.render().unwrap(),
        "

  Test

      No content found

      nav nav nav

"
    );

    let t = FlatDeepBaseTemplate { year: 2018 };
    assert_eq!(
        t.render().unwrap(),
        "

    nav nav nav
    Copyright 2018

"
    );
}
<commit_msg>Add test for let declarations in blocks<commit_after>use askama::Template;

#[derive(Template)]
#[template(path = "base.html")]
struct BaseTemplate<'a> {
    title: &'a str,
}

#[derive(Template)]
#[template(path = "child.html")]
struct ChildTemplate<'a> {
    _parent: BaseTemplate<'a>,
}

#[test]
fn test_use_base_directly() {
    let t = BaseTemplate { title: "Foo" };
    assert_eq!(t.render().unwrap(), "Foo\n\nFoo\nCopyright 2017");
}

#[test]
fn test_simple_extends() {
    let t = ChildTemplate {
        _parent: BaseTemplate { title: "Bar" },
    };
    assert_eq!(
        t.render().unwrap(),
        "Bar\n(Bar) Content goes here\nFoo\nCopyright 2017"
    );
}

#[derive(Template)]
#[template(source = "{% extends \"base.html\" %}", ext = "html")]
struct EmptyChild<'a> {
    title: &'a str,
}

#[test]
fn test_empty_child() {
    let t = EmptyChild { title: "baz" };
    assert_eq!(t.render().unwrap(), "baz\n\nFoo\nCopyright 2017");
}

pub mod parent {
    use askama::Template;
    #[derive(Template)]
    #[template(path = "base.html")]
    pub struct BaseTemplate<'a> {
        pub title: &'a str,
    }
}

pub mod child {
    use super::parent::*;
    use askama::Template;
    #[derive(Template)]
    #[template(path = "child.html")]
    pub struct ChildTemplate<'a> {
        pub _parent: BaseTemplate<'a>,
    }
}

#[test]
fn test_different_module() {
    let t = child::ChildTemplate {
        _parent: parent::BaseTemplate { title: "a" },
    };
    assert_eq!(
        t.render().unwrap(),
        "a\n(a) Content goes here\nFoo\nCopyright 2017"
    );
}

#[derive(Template)]
#[template(path = "nested-base.html")]
struct NestedBaseTemplate {}

#[derive(Template)]
#[template(path = "nested-child.html")]
struct NestedChildTemplate {
    _parent: NestedBaseTemplate,
}

#[test]
fn test_nested_blocks() {
    let t = NestedChildTemplate {
        _parent: NestedBaseTemplate {},
    };
    assert_eq!(t.render().unwrap(), "\ndurpy\n");
}

#[derive(Template)]
#[template(path = "deep-base.html")]
struct DeepBaseTemplate {
    year: u16,
}

#[derive(Template)]
#[template(path = "deep-mid.html")]
struct DeepMidTemplate {
    _parent: DeepBaseTemplate,
    title: String,
}

#[derive(Template)]
#[template(path = "deep-kid.html")]
struct DeepKidTemplate {
    _parent: DeepMidTemplate,
    item: String,
}

#[test]
fn test_deep() {
    let t = DeepKidTemplate {
        _parent: DeepMidTemplate {
            _parent: DeepBaseTemplate { year: 2018 },
            title: "Test".into(),
        },
        item: "Foo".into(),
    };

    assert_eq!(
        t.render().unwrap(),
        "

  Foo Foo Foo

      nav nav nav

"
    );
    assert_eq!(
        t._parent.render().unwrap(),
        "

  Test

      No content found

      nav nav nav

"
    );
    assert_eq!(
        t._parent._parent.render().unwrap(),
        "

    nav nav nav
    Copyright 2018

"
    );
}

#[derive(Template)]
#[template(path = "deep-base.html")]
struct FlatDeepBaseTemplate {
    year: u16,
}

#[derive(Template)]
#[template(path = "deep-mid.html")]
struct FlatDeepMidTemplate {
    title: String,
}

#[derive(Template)]
#[template(path = "deep-kid.html")]
struct FlatDeepKidTemplate {
    item: String,
}

#[test]
fn test_flat_deep() {
    let t = FlatDeepKidTemplate { item: "Foo".into() };

    assert_eq!(
        t.render().unwrap(),
        "

  Foo Foo Foo

      nav nav nav

"
    );

    let t = FlatDeepMidTemplate {
        title: "Test".into(),
    };
    assert_eq!(
        t.render().unwrap(),
        "

  Test

      No content found

      nav nav nav

"
    );

    let t = FlatDeepBaseTemplate { year: 2018 };
    assert_eq!(
        t.render().unwrap(),
        "

    nav nav nav
    Copyright 2018

"
    );
}

#[derive(Template)]
#[template(path = "let-base.html")]
struct LetBase {}

#[derive(Template)]
#[template(path = "let-child.html")]
struct LetChild {}

#[test]
fn test_let_block() {
    let t = LetChild {};
    assert_eq!(t.render().unwrap(), "1");
}<|endoftext|>


<commit_before>use definitions::config::VMConfig;
use definitions::program::Interrupt;
use definitions::typedef::*;
use error::*;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::mouse::MouseButton;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
use sdl2::render::{Canvas, Texture, TextureCreator};
use sdl2::video::{Window, WindowContext};
use std::sync::mpsc::{Receiver, Sender, TryRecvError};

pub fn start(frame_receiver: Receiver<Frame>, interrupt_sender: Sender<Interrupt>, config: VMConfig)
    -> VMResult<()> {
    let sdl_context = sdl2::init()?;
    let video_subsystem = sdl_context.video()?;

    let window = video_subsystem
        .window(
            config.title.as_ref(),
            (config.display.scale * (config.display.resolution.width as Float)).round() as u32,
            (config.display.scale * (config.display.resolution.height as Float)).round() as u32,
        )
        .position_centered()
        .build()
        .chain_err(|| "unable to build window")?;

    let mut canvas = window
        .into_canvas()
        .target_texture()
        .present_vsync()
        .build()
        .chain_err(|| "unable to convert window into canvas")?;

    canvas.set_scale(config.display.scale as f32, config.display.scale as f32)?;

    let mut event_pump = sdl_context.event_pump()?;

    'main: loop {
        // get the inputs here
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    interrupt_sender
                        .send(
                            Interrupt {
                                signal_id: 0,
                                args: Vec::new(),
                            },
                        )
                        .chain_err(|| "unable to send interrupt")?;

                    break 'main;
                }
                _ => {
                    // TODO: Send interrupt here
                }
            }
        }

        // Receive a frame
        let maybe_frame = frame_receiver.try_recv();
        if let Ok(frame) = maybe_frame {

            let mut index = 0;
            for y_coord in 0..config.display.resolution.height {
                for x_coord in 0..config.display.resolution.width {
                    if let Some(raw_color) = frame.get(index) {
                        let r: u8 = (raw_color >> 16) as u8;
                        let g: u8 = (raw_color >> 8) as u8;
                        let b: u8 = *raw_color as u8;

                        canvas.set_draw_color(Color::RGB(r, g, b));

                        canvas.draw_point((x_coord as i32, y_coord as i32))?;
                        index += 1;
                    } else {
                        bail!("no color point available at index {}", index);
                    }
                }
            }

            canvas.present();
        } else if let Err(TryRecvError::Disconnected) = maybe_frame {
            break 'main;
        }
    }

    Ok(())
}
<commit_msg>Removed a few warnings<commit_after>use definitions::config::VMConfig;
use definitions::program::Interrupt;
use definitions::typedef::*;
use error::*;
use sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use std::sync::mpsc::{Receiver, Sender, TryRecvError};

pub fn start(frame_receiver: Receiver<Frame>, interrupt_sender: Sender<Interrupt>, config: VMConfig)
    -> VMResult<()> {
    let sdl_context = sdl2::init()?;
    let video_subsystem = sdl_context.video()?;

    let window = video_subsystem
        .window(
            config.title.as_ref(),
            (config.display.scale * (config.display.resolution.width as Float)).round() as u32,
            (config.display.scale * (config.display.resolution.height as Float)).round() as u32,
        )
        .position_centered()
        .build()
        .chain_err(|| "unable to build window")?;

    let mut canvas = window
        .into_canvas()
        .target_texture()
        .present_vsync()
        .build()
        .chain_err(|| "unable to convert window into canvas")?;

    canvas.set_scale(config.display.scale as f32, config.display.scale as f32)?;

    let mut event_pump = sdl_context.event_pump()?;

    'main: loop {
        // get the inputs here
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    interrupt_sender
                        .send(
                            Interrupt {
                                signal_id: 0,
                                args: Vec::new(),
                            },
                        )
                        .chain_err(|| "unable to send interrupt")?;

                    break 'main;
                }
                _ => {
                    // TODO: Send interrupt here
                }
            }
        }

        // Receive a frame
        let maybe_frame = frame_receiver.try_recv();
        if let Ok(frame) = maybe_frame {

            let mut index = 0;
            for y_coord in 0..config.display.resolution.height {
                for x_coord in 0..config.display.resolution.width {
                    if let Some(raw_color) = frame.get(index) {
                        let r: u8 = (raw_color >> 16) as u8;
                        let g: u8 = (raw_color >> 8) as u8;
                        let b: u8 = *raw_color as u8;

                        canvas.set_draw_color(Color::RGB(r, g, b));

                        canvas.draw_point((x_coord as i32, y_coord as i32))?;
                        index += 1;
                    } else {
                        bail!("no color point available at index {}", index);
                    }
                }
            }

            canvas.present();
        } else if let Err(TryRecvError::Disconnected) = maybe_frame {
            break 'main;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate pagecache;
extern crate sled;
extern crate libc;
extern crate rand;

use std::fs;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 16; // 65536;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (mut k, v) = res.unwrap();
        if v == highest_vec {
            contiguous += 1;
        } else {
            k.reverse();
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    let lowest_vec = u32_to_vec(lowest);

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.scan(&*low_beginning) {
        let (mut k, v) = res.unwrap();
        if v != lowest_vec {
            k.reverse();
        }
        assert_eq!(
            v,
            lowest_vec,
            "expected key {} to have value {}, instead it had value {}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v)
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; 4] = unsafe { std::mem::transmute(u) };
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; 4];
    buf.copy_from_slice(b);

    unsafe { std::mem::transmute(buf) }
}

fn run(config: Config) {
    let tree = sled::Tree::start(config).unwrap();

    // flush to ensure the initial root is stable.
    // TODO is this necessary or voodoo?
    tree.flush().unwrap();

    let (key, highest) = verify(&tree);

    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let mut key = u32_to_vec((hu % CYCLE) as u32);
        key.reverse();
        let value = u32_to_vec((hu / CYCLE) as u32);
        tree.set(key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    run(config);
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(1 << 10)
        .build();

    run(config);
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        let _res = fs::remove_file("test_crashes_with_snapshot/db");
        let _res = fs::remove_file("test_crashes_with_snapshot/conf");

        for dir_entry in fs::read_dir(dir).unwrap() {
            if let Ok(de) = dir_entry {
                let path_buf = de.path();
                let path = path_buf.as_path();
                let path_str = path.to_str().unwrap();
                if path_str.starts_with("test_crashes_with_snapshot/snap.") {
                    let _res = fs::remove_file(path);
                }
            }
        }

        fs::remove_dir_all("test_crashes_with_snapshot").unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        let _res = fs::remove_file("test_crashes/db");
        let _res = fs::remove_file("test_crashes/conf");

        for dir_entry in fs::read_dir(dir).unwrap() {
            if let Ok(de) = dir_entry {
                let path_buf = de.path();
                let path = path_buf.as_path();
                let path_str = path.to_str().unwrap();
                if path_str.starts_with("test_crashes/snap.") {
                    let _res = fs::remove_file(path);
                }
            }
        }

        fs::remove_dir_all("test_crashes").unwrap();
    }
}
<commit_msg>don't run crash tests on fuschia or android<commit_after>#![cfg(all(not(target_os = "fuschia"), not(target_os = "android")))]

extern crate pagecache;
extern crate sled;
extern crate libc;
extern crate rand;

use std::fs;
use std::path::Path;
use std::thread;
use std::time::Duration;

use rand::Rng;

use pagecache::{Config, ConfigBuilder};

const CYCLE: usize = 16; // 65536;

/// Verifies that the keys in the tree are correctly recovered.
/// Panics if they are incorrect.
/// Returns the key that should be resumed at, and the current cycle value.
fn verify(tree: &sled::Tree) -> (u32, u32) {
    // key 0 should always be the highest value, as that's where we increment
    // at some point, it might go down by one
    // it should never return, or go down again after that
    let mut iter = tree.iter();
    let highest = match iter.next() {
        Some(Ok((_k, v))) => slice_to_u32(&*v),
        Some(Err(e)) => panic!("{:?}", e),
        None => return (0, 0),
    };

    let highest_vec = u32_to_vec(highest);

    // find how far we got
    let mut contiguous: u32 = 0;
    let mut lowest = 0;
    for res in iter {
        let (mut k, v) = res.unwrap();
        if v == highest_vec {
            contiguous += 1;
        } else {
            k.reverse();
            let expected = if highest == 0 {
                CYCLE as u32 - 1
            } else {
                (highest - 1) % CYCLE as u32
            };
            let actual = slice_to_u32(&*v);
            assert_eq!(expected, actual);
            lowest = actual;
            break;
        }
    }

    let lowest_vec = u32_to_vec(lowest);

    // ensure nothing changes after this point
    let low_beginning = u32_to_vec(contiguous + 1);

    for res in tree.scan(&*low_beginning) {
        let (mut k, v) = res.unwrap();
        if v != lowest_vec {
            k.reverse();
        }
        assert_eq!(
            v,
            lowest_vec,
            "expected key {} to have value {}, instead it had value {}",
            slice_to_u32(&*k),
            lowest,
            slice_to_u32(&*v)
        );
    }

    (contiguous, highest)
}

fn u32_to_vec(u: u32) -> Vec<u8> {
    let buf: [u8; 4] = unsafe { std::mem::transmute(u) };
    buf.to_vec()
}

fn slice_to_u32(b: &[u8]) -> u32 {
    let mut buf = [0u8; 4];
    buf.copy_from_slice(b);

    unsafe { std::mem::transmute(buf) }
}

fn run(config: Config) {
    let tree = sled::Tree::start(config).unwrap();

    // flush to ensure the initial root is stable.
    // TODO is this necessary or voodoo?
    tree.flush().unwrap();

    let (key, highest) = verify(&tree);

    thread::spawn(|| {
        let runtime = rand::thread_rng().gen_range(0, 200);
        thread::sleep(Duration::from_millis(runtime));
        unsafe {
            libc::raise(9);
        }
    });

    let mut hu = ((highest as usize) * CYCLE) + key as usize;
    assert_eq!(hu % CYCLE, key as usize);
    assert_eq!(hu / CYCLE, highest as usize);

    loop {
        hu += 1;

        if hu / CYCLE >= CYCLE {
            hu = 0;
        }

        let mut key = u32_to_vec((hu % CYCLE) as u32);
        key.reverse();
        let value = u32_to_vec((hu / CYCLE) as u32);
        tree.set(key, value).unwrap();
    }
}

fn run_without_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes".to_string())
        .snapshot_after_ops(1 << 56)
        .build();

    run(config);
}

fn run_with_snapshot() {
    let config = ConfigBuilder::new()
        .io_bufs(2)
        .blink_fanout(15)
        .page_consolidation_threshold(10)
        .cache_fixup_threshold(1)
        .cache_bits(6)
        .cache_capacity(128 * 1024 * 1024)
        .flush_every_ms(Some(100))
        // drop io_buf_size to 1<<16, then 1<<17 to tease out
        // low hanging fruit more quickly
        .io_buf_size(100_000) // 1<<16 is 65k but might cause stalling
        .path("test_crashes_with_snapshot".to_string())
        .snapshot_after_ops(1 << 10)
        .build();

    run(config);
}

#[test]
fn test_crash_recovery_with_runtime_snapshot() {
    cleanup_with_snapshots();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_with_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup_with_snapshots();
}

#[test]
fn test_crash_recovery_no_runtime_snapshot() {
    cleanup();
    for _ in 0..100 {
        let child = unsafe { libc::fork() };
        if child == 0 {
            run_without_snapshot()
        } else {
            let mut status = 0;
            unsafe {
                libc::waitpid(child, &mut status as *mut libc::c_int, 0);
            }
            if status != 9 {
                cleanup();
                panic!("child exited abnormally");
            }
        }
    }
    cleanup();
}

fn cleanup_with_snapshots() {
    let dir = Path::new("test_crashes_with_snapshot");
    if dir.exists() {
        let _res = fs::remove_file("test_crashes_with_snapshot/db");
        let _res = fs::remove_file("test_crashes_with_snapshot/conf");

        for dir_entry in fs::read_dir(dir).unwrap() {
            if let Ok(de) = dir_entry {
                let path_buf = de.path();
                let path = path_buf.as_path();
                let path_str = path.to_str().unwrap();
                if path_str.starts_with("test_crashes_with_snapshot/snap.") {
                    let _res = fs::remove_file(path);
                }
            }
        }

        fs::remove_dir_all("test_crashes_with_snapshot").unwrap();
    }
}

fn cleanup() {
    let dir = Path::new("test_crashes");
    if dir.exists() {
        let _res = fs::remove_file("test_crashes/db");
        let _res = fs::remove_file("test_crashes/conf");

        for dir_entry in fs::read_dir(dir).unwrap() {
            if let Ok(de) = dir_entry {
                let path_buf = de.path();
                let path = path_buf.as_path();
                let path_str = path.to_str().unwrap();
                if path_str.starts_with("test_crashes/snap.") {
                    let _res = fs::remove_file(path);
                }
            }
        }

        fs::remove_dir_all("test_crashes").unwrap();
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::path::Path;

use gltf;
use gltf_importer;

use camera::Camera;
use render::math::*;
use render::mesh::Mesh;
use render::scene::Scene;

pub struct Node {
    // TODO!!: handle camera in Node
    pub children: Vec<Node>,
    pub matrix: Matrix4,
    pub mesh: Option<Rc<Mesh>>,
    pub rotation: Quaternion,
    pub scale: Vector3,
    pub translation: Vector3,
    // TODO: weights
    // weights_id: usize,
    pub name: Option<String>,

    final_transform: Matrix4, // including parent transforms
    model_loc: Option<i32>,

    pub bounds: Bounds,
}

impl Node {
    pub fn from_gltf(
        g_node: gltf::Node,
        scene: &mut Scene,
        buffers: &gltf_importer::Buffers,
        base_path: &Path
    ) -> Node {
        // convert matrix in 3 steps due to type system weirdness
        let matrix = &g_node.matrix();
        let matrix: &Matrix4 = matrix.into();
        let matrix = *matrix;

        let r = &g_node.rotation();
        let rotation = Quaternion::new(r[3], r[0], r[1], r[2]); // NOTE: different element order!

        let mut mesh = None;
        if let Some(g_mesh) = g_node.mesh() {
            if let Some(existing_mesh) = scene.meshes.iter().find(|mesh| (***mesh).index == g_mesh.index()) {
                mesh = Some(Rc::clone(existing_mesh));
            }

            if mesh.is_none() { // not using else due to borrow-checking madness
                mesh = Some(Rc::new(Mesh::from_gltf(g_mesh, scene, buffers, base_path)));
                scene.meshes.push(mesh.clone().unwrap());
            }
        }
        let children: Vec<_> = g_node.children()
                .map(|g_node| Node::from_gltf(g_node, scene, buffers, base_path))
                .collect();

        Node {
            children,
            matrix,
            mesh,
            rotation,
            // TODO!!: use of deprecated item: Use `transform().decomposed()` instead.
            scale: g_node.scale().into(),
            translation: g_node.translation().into(),
            name: g_node.name().map(|s| s.into()),

            final_transform: Matrix4::identity(),
            model_loc: None,

            bounds: Bounds::default(),
        }
    }

    pub fn update_transform(&mut self, parent_transform: &Matrix4) {
        self.final_transform = *parent_transform;

        if !self.matrix.is_identity() {
            self.final_transform = self.final_transform * self.matrix;
        }
        else {
            // TODO?: detect if all default and set None? does NOT happen for any sample model
            self.final_transform = self.final_transform *
                Matrix4::from_translation(self.translation) *
                Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z) *
                Matrix4::from(self.rotation);
        }

        for node in &mut self.children {
            node.update_transform(&self.final_transform);
        }
    }

    /// Should be called after update_transforms
    pub fn update_bounds(&mut self) {
        self.bounds = Default::default();
        if let Some(ref mesh) = self.mesh {
            self.bounds = mesh.bounds
                .transform(&self.final_transform);
        }
        else if self.children.is_empty() {
            // Cameras (others?) have neither mesh nor children. Their position is the origin
            // TODO!: are there other cases? Do bounds matter for cameras?
            self.bounds = Bounds { min: Vector3::zero(), max: Vector3::zero() };
            self.bounds = self.bounds.transform(&self.final_transform);
        }
        else {
            for node in &mut self.children {
                node.update_bounds();
                self.bounds = self.bounds.union(&node.bounds);
            }
        }
    }

    pub fn draw(&mut self, camera: &Camera) {
        if let Some(ref mesh) = self.mesh {
            let mvp_matrix = camera.projection_matrix() * camera.view_matrix() * self.final_transform;

            (*mesh).draw(&self.final_transform, &mvp_matrix, &camera.position.to_vec());
        }
        for node in &mut self.children {
            node.draw(camera);
        }
    }
}
<commit_msg>allow deprecated transform functions, but add TODO<commit_after>use std::rc::Rc;
use std::path::Path;

use gltf;
use gltf_importer;

use camera::Camera;
use render::math::*;
use render::mesh::Mesh;
use render::scene::Scene;

pub struct Node {
    // TODO!!: handle camera in Node
    pub children: Vec<Node>,
    pub matrix: Matrix4,
    pub mesh: Option<Rc<Mesh>>,
    pub rotation: Quaternion,
    pub scale: Vector3,
    pub translation: Vector3,
    // TODO: weights
    // weights_id: usize,
    pub name: Option<String>,

    final_transform: Matrix4, // including parent transforms
    model_loc: Option<i32>,

    pub bounds: Bounds,
}

impl Node {
    // TODO!: refactor transformations using mint and non-deprecated functions
    #[allow(deprecated)]
    pub fn from_gltf(
        g_node: gltf::Node,
        scene: &mut Scene,
        buffers: &gltf_importer::Buffers,
        base_path: &Path
    ) -> Node {
        // convert matrix in 3 steps due to type system weirdness
        let matrix = &g_node.matrix();
        let matrix: &Matrix4 = matrix.into();
        let matrix = *matrix;

        let r = &g_node.rotation();
        let rotation = Quaternion::new(r[3], r[0], r[1], r[2]); // NOTE: different element order!

        let mut mesh = None;
        if let Some(g_mesh) = g_node.mesh() {
            if let Some(existing_mesh) = scene.meshes.iter().find(|mesh| (***mesh).index == g_mesh.index()) {
                mesh = Some(Rc::clone(existing_mesh));
            }

            if mesh.is_none() { // not using else due to borrow-checking madness
                mesh = Some(Rc::new(Mesh::from_gltf(g_mesh, scene, buffers, base_path)));
                scene.meshes.push(mesh.clone().unwrap());
            }
        }
        let children: Vec<_> = g_node.children()
                .map(|g_node| Node::from_gltf(g_node, scene, buffers, base_path))
                .collect();

        Node {
            children,
            matrix,
            mesh,
            rotation,
            scale: g_node.scale().into(),
            translation: g_node.translation().into(),
            name: g_node.name().map(|s| s.into()),

            final_transform: Matrix4::identity(),
            model_loc: None,

            bounds: Bounds::default(),
        }
    }

    pub fn update_transform(&mut self, parent_transform: &Matrix4) {
        self.final_transform = *parent_transform;

        if !self.matrix.is_identity() {
            self.final_transform = self.final_transform * self.matrix;
        }
        else {
            // TODO?: detect if all default and set None? does NOT happen for any sample model
            self.final_transform = self.final_transform *
                Matrix4::from_translation(self.translation) *
                Matrix4::from_nonuniform_scale(self.scale.x, self.scale.y, self.scale.z) *
                Matrix4::from(self.rotation);
        }

        for node in &mut self.children {
            node.update_transform(&self.final_transform);
        }
    }

    /// Should be called after update_transforms
    pub fn update_bounds(&mut self) {
        self.bounds = Default::default();
        if let Some(ref mesh) = self.mesh {
            self.bounds = mesh.bounds
                .transform(&self.final_transform);
        }
        else if self.children.is_empty() {
            // Cameras (others?) have neither mesh nor children. Their position is the origin
            // TODO!: are there other cases? Do bounds matter for cameras?
            self.bounds = Bounds { min: Vector3::zero(), max: Vector3::zero() };
            self.bounds = self.bounds.transform(&self.final_transform);
        }
        else {
            for node in &mut self.children {
                node.update_bounds();
                self.bounds = self.bounds.union(&node.bounds);
            }
        }
    }

    pub fn draw(&mut self, camera: &Camera) {
        if let Some(ref mesh) = self.mesh {
            let mvp_matrix = camera.projection_matrix() * camera.view_matrix() * self.final_transform;

            (*mesh).draw(&self.final_transform, &mvp_matrix, &camera.position.to_vec());
        }
        for node in &mut self.children {
            node.draw(camera);
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*!
The representation of CSS property values

Enums are named after the property. Variants have the same name + the
name of the value used in the spec. This leads to some verbose names,
e.g.:

The property 'background-color' and the specified value called '<color>'
in the spec lead to the variant CSSBackgroundColorColor(Color).

At least it's consistent though.
*/

use std::cmp::Eq;
use extra::net::url::Url;
use units::{Length, AbsoluteSize, RelativeSize};
use units::GenericFontFamily;
use color::Color;

/** A partial CSS value, before inheritance has been resolved */
#[deriving(Eq)]
pub enum CSSValue<T> {
    Inherit,
    Specified(T),
}

// CSS 2.1, Section 8 - Box model

#[deriving(Eq)]
pub enum CSSMargin {
    CSSMarginLength(Length),
    CSSMarginPercentage(float),
    CSSMarginAuto
}

pub enum CSSPadding {
    CSSPaddingLength(Length),
    CSSPaddingPercentage(float)
}

#[deriving(Eq)]
pub enum CSSBorderWidth {
    CSSBorderWidthThin,
    CSSBorderWidthMedium,
    CSSBorderWidthThick,
    CSSBorderWidthLength(Length)
}

pub enum CSSBorderColor {
    CSSBorderColorColor(Color),
    CSSBorderColorTransparent
}

pub enum CSSBorderStyle {
    CSSBorderStyleNone,
    CSSBorderStyleHidden,
    CSSBorderStyleDotted,
    CSSBorderStyleDashed,
    CSSBorderStyleSolid,
    CSSBorderStyleDouble,
    CSSBorderStyleGroove,
    CSSBorderStyleRidge,
    CSSBorderStyleInset,
    CSSBorderStyleOutset,
}

// CSS 2.1, Section 9 - Visual formatting model

#[deriving(Eq)]
pub enum CSSDisplay {
    CSSDisplayInline,
    CSSDisplayBlock,
    CSSDisplayListItem,
    CSSDisplayInlineBlock,
    CSSDisplayTable,
    CSSDisplayInlineTable,
    CSSDisplayTableRowGroup,
    CSSDisplayTableHeaderGroup,
    CSSDisplayTableFooterGroup,
    CSSDisplayTableRow,
    CSSDisplayTableColumnGroup,
    CSSDisplayTableColumn,
    CSSDisplayTableCell,
    CSSDisplayTableCaption,
    CSSDisplayNone
}

#[deriving(Eq)]
pub enum CSSPosition {
    CSSPositionStatic,
    CSSPositionRelative,
    CSSPositionAbsolute,
    CSSPositionFixed
}

pub enum CSSTop {
    CSSTopLength(Length),
    CSSTopPercentage,
    CSSTopAuto
}

pub enum CSSRight {
    CSSRightLength(Length),
    CSSRightPercentage(float),
    CSSRightAuto
}

pub enum CSSBottom {
    CSSBottomLength(Length),
    CSSBottomPercentage(float),
    CSSBottomAuto
}

pub enum CSSLeft {
    CSSLeftLength(Length),
    CSSLeftPercentage(float),
    CSSLeftAuto
}

#[deriving(Eq)]
pub enum CSSFloat {
    CSSFloatLeft,
    CSSFloatRight,
    CSSFloatNone
}

pub enum CSSDirection {
    CSSDirectionLtr,
    CSSDirectionRtl
}

// CSS 2.1, Section 10 - Visual formatting model details

#[deriving(Eq)]
pub enum CSSWidth {
    CSSWidthLength(Length),
    CSSWidthPercentage(float),
    CSSWidthAuto
}

#[deriving(Eq)]
pub enum CSSHeight {
    CSSHeightLength(Length),
    CSSHeightPercentage(float),
    CSSHeightAuto
}

#[deriving(Eq)]
pub enum CSSLineHeight {
    CSSLineHeightNormal,
    CSSLineHeightNumber(float),
    CSSLineHeightLength(Length),
    CSSLineHeightPercentage(float),
}

pub enum CSSVerticalAlign {
    CSSVerticalAlignBaseline,
    CSSVerticalAlignSub,
    CSSVerticalAlignSuper,
    CSSVerticalAlignTop,
    CSSVerticalAlignTextTop,
    CSSVerticalAlignMiddle,
    CSSVerticalAlignBottom,
    CSSVerticalAlignTextBottom,
    CSSVerticalAlignPercentage(float),
    CSSVerticalAlignLength(Length),
}

// CSS 2.1, Section 11 - Visual effects

pub enum CSSOverflow {
    CSSOverflowVisible,
    CSSOverflowHidden,
    CSSOverflowScroll,
    CSSOverflowAuto
}

pub enum CSSVisibility {
    CSSVisibilityVisible,
    CSSVisibilityHidden,
    CSSVisibilityCollapse
}

// CSS 2.1, Section 12 - Generated content, automatic numbering, and lists

// CSS 2.1, Section 13 - Paged media

// CSS 2.1, Section 14 - Colors and Backgrounds

#[deriving(Eq)]
pub enum CSSColor {
    CSSColorColor(Color)
}

#[deriving(Eq)]
pub enum CSSBackgroundColor {
    CSSBackgroundColorColor(Color),
    CSSBackgroundColorTransparent
}

pub enum CSSBackgroundImage {
    CSSBackgroundUri(Url),
    CSSBackgroundImageNone
}

pub enum CSSBackgroundRepeat {
    CSSBackgroundRepeatRepeat,
    CSSBackgroundRepeatRepeatX,
    CSSBackgroundRepeatRepeatY,
    CSSBackgroundRepeatNoRepeat
}

pub enum CSSBackgroundAttachment {
    CSSBackgroundAttachmentScroll,
    CSSBackgroundAttachmentFixed
}

pub enum CSSBackgroundPosition {
    CSSBackgroundPositionPercentage(float),
    CSSBackgroundPositionLength(Length),
    CSSBackgroundPositionLeft,
    CSSBackgroundPositionCenter,
    CSSBackgroundPositionRight,
    CSSBackgroundPositionTop,
    CSSBackgroundPositionBottom
}

// CSS 2.1, Section 15 - Fonts

#[deriving(Eq)]
pub enum CSSFontFamily {
    CSSFontFamilyFamilyName(~str),
    CSSFontFamilyGenericFamily(GenericFontFamily)
}

#[deriving(Eq)]
pub enum CSSFontStyle {
    CSSFontStyleNormal,
    CSSFontStyleItalic,
    CSSFontStyleOblique
}

#[deriving(Eq)]
pub enum CSSFontWeight {
    CSSFontWeightNormal,
    CSSFontWeightBold,
    CSSFontWeightBolder,
    CSSFontWeightLighter,
    CSSFontWeight100,
    CSSFontWeight200,
    CSSFontWeight300,
    CSSFontWeight400,
    CSSFontWeight500,
    CSSFontWeight600,
    CSSFontWeight700,
    CSSFontWeight800,
    CSSFontWeight900
}

#[deriving(Eq)]
pub enum CSSFontSize {
    CSSFontSizeAbsoluteSize(AbsoluteSize),
    CSSFontSizeRelativeSize(RelativeSize),
    CSSFontSizeLength(Length),
    CSSFontSizePercentage(float)
}

// CSS 2.1, Section 16 - Text

#[deriving(Eq)]
pub enum CSSTextAlign {
    CSSTextAlignLeft,
    CSSTextAlignRight,
    CSSTextAlignCenter,
    CSSTextAlignJustify
}

#[deriving(Eq)]
pub enum CSSTextDecoration {
    CSSTextDecorationNone,
    CSSTextDecorationUnderline,
    CSSTextDecorationOverline,
    CSSTextDecorationLineThrough,
    CSSTextDecorationBlink
}

pub enum CSSTextTransform {
    CSSTextTransformCapitalize,
    CSSTextTransformUppercase,
    CSSTextTransformLowercase,
    CSSTextTransformNone
}

// CSS 2.1, Section 17 - Tables

// CSS 2.1, Section 18 - User interface

<commit_msg>Derive Eq on all values<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*!
The representation of CSS property values

Enums are named after the property. Variants have the same name + the
name of the value used in the spec. This leads to some verbose names,
e.g.:

The property 'background-color' and the specified value called '<color>'
in the spec lead to the variant CSSBackgroundColorColor(Color).

At least it's consistent though.
*/

use std::cmp::Eq;
use extra::net::url::Url;
use units::{Length, AbsoluteSize, RelativeSize};
use units::GenericFontFamily;
use color::Color;

/** A partial CSS value, before inheritance has been resolved */
#[deriving(Eq)]
pub enum CSSValue<T> {
    Inherit,
    Specified(T),
}

// CSS 2.1, Section 8 - Box model

#[deriving(Eq)]
pub enum CSSMargin {
    CSSMarginLength(Length),
    CSSMarginPercentage(float),
    CSSMarginAuto
}

#[deriving(Eq)]
pub enum CSSPadding {
    CSSPaddingLength(Length),
    CSSPaddingPercentage(float)
}

#[deriving(Eq)]
pub enum CSSBorderWidth {
    CSSBorderWidthThin,
    CSSBorderWidthMedium,
    CSSBorderWidthThick,
    CSSBorderWidthLength(Length)
}

#[deriving(Eq)]
pub enum CSSBorderColor {
    CSSBorderColorColor(Color),
    CSSBorderColorTransparent
}

#[deriving(Eq)]
pub enum CSSBorderStyle {
    CSSBorderStyleNone,
    CSSBorderStyleHidden,
    CSSBorderStyleDotted,
    CSSBorderStyleDashed,
    CSSBorderStyleSolid,
    CSSBorderStyleDouble,
    CSSBorderStyleGroove,
    CSSBorderStyleRidge,
    CSSBorderStyleInset,
    CSSBorderStyleOutset,
}

// CSS 2.1, Section 9 - Visual formatting model

#[deriving(Eq)]
pub enum CSSDisplay {
    CSSDisplayInline,
    CSSDisplayBlock,
    CSSDisplayListItem,
    CSSDisplayInlineBlock,
    CSSDisplayTable,
    CSSDisplayInlineTable,
    CSSDisplayTableRowGroup,
    CSSDisplayTableHeaderGroup,
    CSSDisplayTableFooterGroup,
    CSSDisplayTableRow,
    CSSDisplayTableColumnGroup,
    CSSDisplayTableColumn,
    CSSDisplayTableCell,
    CSSDisplayTableCaption,
    CSSDisplayNone
}

#[deriving(Eq)]
pub enum CSSPosition {
    CSSPositionStatic,
    CSSPositionRelative,
    CSSPositionAbsolute,
    CSSPositionFixed
}

#[deriving(Eq)]
pub enum CSSTop {
    CSSTopLength(Length),
    CSSTopPercentage,
    CSSTopAuto
}

#[deriving(Eq)]
pub enum CSSRight {
    CSSRightLength(Length),
    CSSRightPercentage(float),
    CSSRightAuto
}

#[deriving(Eq)]
pub enum CSSBottom {
    CSSBottomLength(Length),
    CSSBottomPercentage(float),
    CSSBottomAuto
}

#[deriving(Eq)]
pub enum CSSLeft {
    CSSLeftLength(Length),
    CSSLeftPercentage(float),
    CSSLeftAuto
}

#[deriving(Eq)]
pub enum CSSFloat {
    CSSFloatLeft,
    CSSFloatRight,
    CSSFloatNone
}

#[deriving(Eq)]
pub enum CSSDirection {
    CSSDirectionLtr,
    CSSDirectionRtl
}

// CSS 2.1, Section 10 - Visual formatting model details

#[deriving(Eq)]
pub enum CSSWidth {
    CSSWidthLength(Length),
    CSSWidthPercentage(float),
    CSSWidthAuto
}

#[deriving(Eq)]
pub enum CSSHeight {
    CSSHeightLength(Length),
    CSSHeightPercentage(float),
    CSSHeightAuto
}

#[deriving(Eq)]
pub enum CSSLineHeight {
    CSSLineHeightNormal,
    CSSLineHeightNumber(float),
    CSSLineHeightLength(Length),
    CSSLineHeightPercentage(float),
}

#[deriving(Eq)]
pub enum CSSVerticalAlign {
    CSSVerticalAlignBaseline,
    CSSVerticalAlignSub,
    CSSVerticalAlignSuper,
    CSSVerticalAlignTop,
    CSSVerticalAlignTextTop,
    CSSVerticalAlignMiddle,
    CSSVerticalAlignBottom,
    CSSVerticalAlignTextBottom,
    CSSVerticalAlignPercentage(float),
    CSSVerticalAlignLength(Length),
}

// CSS 2.1, Section 11 - Visual effects

#[deriving(Eq)]
pub enum CSSOverflow {
    CSSOverflowVisible,
    CSSOverflowHidden,
    CSSOverflowScroll,
    CSSOverflowAuto
}

#[deriving(Eq)]
pub enum CSSVisibility {
    CSSVisibilityVisible,
    CSSVisibilityHidden,
    CSSVisibilityCollapse
}

// CSS 2.1, Section 12 - Generated content, automatic numbering, and lists

// CSS 2.1, Section 13 - Paged media

// CSS 2.1, Section 14 - Colors and Backgrounds

#[deriving(Eq)]
pub enum CSSColor {
    CSSColorColor(Color)
}

#[deriving(Eq)]
pub enum CSSBackgroundColor {
    CSSBackgroundColorColor(Color),
    CSSBackgroundColorTransparent
}

#[deriving(Eq)]
pub enum CSSBackgroundImage {
    CSSBackgroundUri(Url),
    CSSBackgroundImageNone
}

#[deriving(Eq)]
pub enum CSSBackgroundRepeat {
    CSSBackgroundRepeatRepeat,
    CSSBackgroundRepeatRepeatX,
    CSSBackgroundRepeatRepeatY,
    CSSBackgroundRepeatNoRepeat
}

#[deriving(Eq)]
pub enum CSSBackgroundAttachment {
    CSSBackgroundAttachmentScroll,
    CSSBackgroundAttachmentFixed
}

#[deriving(Eq)]
pub enum CSSBackgroundPosition {
    CSSBackgroundPositionPercentage(float),
    CSSBackgroundPositionLength(Length),
    CSSBackgroundPositionLeft,
    CSSBackgroundPositionCenter,
    CSSBackgroundPositionRight,
    CSSBackgroundPositionTop,
    CSSBackgroundPositionBottom
}

// CSS 2.1, Section 15 - Fonts

#[deriving(Eq)]
pub enum CSSFontFamily {
    CSSFontFamilyFamilyName(~str),
    CSSFontFamilyGenericFamily(GenericFontFamily)
}

#[deriving(Eq)]
pub enum CSSFontStyle {
    CSSFontStyleNormal,
    CSSFontStyleItalic,
    CSSFontStyleOblique
}

#[deriving(Eq)]
pub enum CSSFontWeight {
    CSSFontWeightNormal,
    CSSFontWeightBold,
    CSSFontWeightBolder,
    CSSFontWeightLighter,
    CSSFontWeight100,
    CSSFontWeight200,
    CSSFontWeight300,
    CSSFontWeight400,
    CSSFontWeight500,
    CSSFontWeight600,
    CSSFontWeight700,
    CSSFontWeight800,
    CSSFontWeight900
}

#[deriving(Eq)]
pub enum CSSFontSize {
    CSSFontSizeAbsoluteSize(AbsoluteSize),
    CSSFontSizeRelativeSize(RelativeSize),
    CSSFontSizeLength(Length),
    CSSFontSizePercentage(float)
}

// CSS 2.1, Section 16 - Text

#[deriving(Eq)]
pub enum CSSTextAlign {
    CSSTextAlignLeft,
    CSSTextAlignRight,
    CSSTextAlignCenter,
    CSSTextAlignJustify
}

#[deriving(Eq)]
pub enum CSSTextDecoration {
    CSSTextDecorationNone,
    CSSTextDecorationUnderline,
    CSSTextDecorationOverline,
    CSSTextDecorationLineThrough,
    CSSTextDecorationBlink
}

#[deriving(Eq)]
pub enum CSSTextTransform {
    CSSTextTransformCapitalize,
    CSSTextTransformUppercase,
    CSSTextTransformLowercase,
    CSSTextTransformNone
}

// CSS 2.1, Section 17 - Tables

// CSS 2.1, Section 18 - User interface

<|endoftext|>