<commit_before>use utils::u256::U256;
use utils::gas::Gas;
use super::Opcode;
use vm::{Machine, Memory, Stack, PC};
use transaction::Transaction;

use std::ops::{Add, Sub, Not, Mul, Div, Shr, Shl, BitAnd, BitOr, BitXor};
use crypto::sha3::Sha3;
use crypto::digest::Digest;

fn signed_abs(v: U256) -> U256 {
    let negative: U256 = U256::one() << 256;

    if v >= negative {
        !v + 1.into()
    } else {
        v
    }
}

macro_rules! op2 {
    ( $machine:expr, $op:ident ) => ({
        let op1 = $machine.stack_mut().pop();
        let op2 = $machine.stack_mut().pop();
        $machine.stack_mut().push(op1.$op(op2));
    })
}

macro_rules! op2_ref {
    ( $machine:expr, $op:ident ) => ({
        let op1 = $machine.stack_mut().pop();
        let op2 = $machine.stack_mut().pop();
        $machine.stack_mut().push(op1.$op(&op2).into());
    })
}

impl Opcode {
    pub fn run<M: Machine>(&self, machine: &mut M) {
        let opcode = self.clone();

        match opcode {
            Opcode::STOP => {
                machine.pc_mut().stop();
            },

            Opcode::ADD => op2!(machine, add),
            Opcode::MUL => op2!(machine, mul),
            Opcode::SUB => op2!(machine, sub),

            Opcode::DIV => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(op1 / op2);
                }
            },

            Opcode::SDIV => {
                // This is signed division. So the U256 would need to
                // be treated as signed two's complement. We currently
                // convert it to both positive, and then deal with the
                // sign afterwards...

                let negative: U256 = U256::one() << 256;
                // This value is also -2^255 in two's complement.
                let max: U256 = U256::max_value();
                // This value is also -1 in two's complement.

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else if op1 == negative && op2 == max {
                    machine.stack_mut().push(negative);
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = op1 / op2;

                    if (op1 < negative && op2 < negative) || (op1 >= negative && op2 >= negative) {
                        machine.stack_mut().push(r);
                    } else {
                        let sr = !r + 1.into();
                        machine.stack_mut().push(sr);
                    }
                }
            },

            Opcode::MOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(op1 - (op1 / op2) * op2);
                }
            },

            Opcode::SMOD => {
                let negative: U256 = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = aop1 - (aop1 / aop2) * aop2;
                    if op1 < negative && op2 < negative {
                        machine.stack_mut().push(r);
                    } else if op1 >= negative && op2 < negative {
                        machine.stack_mut().push(!(op1 + r) + 1.into());
                    } else if op1 < negative && op2 >= negative {
                        machine.stack_mut().push(op1 + r);
                    } else if op1 >= negative && op2 >= negative {
                        machine.stack_mut().push(!r + 1.into());
                    }
                }
            },

            Opcode::ADDMOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                let op3 = machine.stack_mut().pop();

                if op3 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    // TODO: Handle the case where op1 + op2 > 2^256
                    let v = op1 + op2;
                    machine.stack_mut().push(v - (v / op3) * op3);
                }
            },

            Opcode::MULMOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                let op3 = machine.stack_mut().pop();

                if op3 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    // TODO: Handle the case where op1 * op2 > 2^256
                    let v = op1 * op2;
                    machine.stack_mut().push(v - (v / op3) * op3);
                }
            },

            Opcode::EXP => {
                let op1 = machine.stack_mut().pop();
                let mut op2 = machine.stack_mut().pop();
                let mut r: U256 = 1.into();

                while op2 != 0.into() {
                    r = r * op1;
                    op2 = op2 - 1.into();
                }
                machine.stack_mut().push(r);
            },

            Opcode::SIGNEXTEND => {
                // TODO: Check this confines with the yello paper

                let mut op1 = machine.stack_mut().pop();
                let mut op2 = machine.stack_mut().pop();

                let mut negative: U256 = 1.into();
                let mut s = 0;
                while op2 != 0.into() {
                    negative = U256::one() << s;
                    s = s + 1;
                    op2 = op2 - 1.into();
                }

                if op1 >= negative {
                    while s <= 256 {
                        op1 = op1 + (U256::one() << s);
                        s = s + 1;
                    }
                    machine.stack_mut().push(op1);
                } else {
                    machine.stack_mut().push(op1);
                }
            },

            Opcode::LT => op2_ref!(machine, lt),
            Opcode::GT => op2_ref!(machine, gt),

            Opcode::SLT => {
                let negative = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op1 < negative && op2 < negative {
                    if op1 < op2 {
                        machine.stack_mut().push(1.into());
                    } else {
                        machine.stack_mut().push(0.into());
                    }
                } else if op2 >= negative && op2 >= negative {
                    if op1 < op2 {
                        machine.stack_mut().push(0.into());
                    } else {
                        machine.stack_mut().push(1.into());
                    }
                } else if op1 < negative && op2 >= negative {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(1.into());
                }
            },

            Opcode::SGT => {
                let negative = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op1 < negative && op2 < negative {
                    if op1 < op2 {
                        machine.stack_mut().push(0.into());
                    } else {
                        machine.stack_mut().push(1.into());
                    }
                } else if op2 >= negative && op2 >= negative {
                    if op1 < op2 {
                        machine.stack_mut().push(1.into());
                    } else {
                        machine.stack_mut().push(0.into());
                    }
                } else if op1 < negative && op2 >= negative {
                    machine.stack_mut().push(1.into());
                } else {
                    machine.stack_mut().push(0.into());
                }
            },

            Opcode::EQ => op2_ref!(machine, eq),

            Opcode::ISZERO => {
                let op1 = machine.stack_mut().pop();

                if op1 == 0.into() {
                    machine.stack_mut().push(1.into());
                } else {
                    machine.stack_mut().push(0.into());
                }
            },

            Opcode::AND => op2!(machine, bitand),
            Opcode::OR => op2!(machine, bitor),
            Opcode::XOR => op2!(machine, bitxor),

            Opcode::NOT => {
                let op1 = machine.stack_mut().pop();

                machine.stack_mut().push(!op1);
            },

            Opcode::BYTE => {
                let op1 = machine.stack_mut().pop();
                let op2: usize = machine.stack_mut().pop().into(); // 256 / 8
                let mark: U256 = 0xff.into();

                if op2 >= 256 / 8 {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push((op1 >> (op2 * 8)) & mark);
                }
            },

            Opcode::SHA3 => {
                let mut op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                let mut r: [u8; 32] = [0u8; 32];
                let mut sha3 = Sha3::keccak256();

                while op1 != op2 - 1.into() {
                    let val = machine.memory_mut().read(op1);
                    sha3.input(val.as_ref());
                    op1 = op1 + 1.into();
                }
                sha3.result(&mut r);
                machine.stack_mut().push(U256::from(r.as_ref()))
            },

            // TODO: implement opcode 0x21 to 0x4f

            Opcode::POP => {
                machine.stack_mut().pop();
            },

            Opcode::MLOAD => {
                let op1 = machine.stack_mut().pop();
                let val = machine.memory_mut().read(op1);
                // u_i update is automatically handled by Memory.
                machine.stack_mut().push(val);
            },

            Opcode::MSTORE => {
                let op1 = machine.stack_mut().pop(); // Index
                let op2 = machine.stack_mut().pop(); // Data
                // u_i update is automatically handled by Memory.
                machine.memory_mut().write(op1, op2);
            },

            // TODO: implement storage related opcode SLOAD, SSTORE

            Opcode::JUMP => {
                let op1_u: u64 = machine.stack_mut().pop().into();
                machine.pc_mut().jump(op1_u as usize);
            },

            Opcode::JUMPI => {
                let op1_u: u64 = machine.stack_mut().pop().into();
                let op2 = machine.stack_mut().pop();

                if op2 != 0.into() {
                    machine.pc_mut().jump(op1_u as usize);
                }
            },

            Opcode::PC => {
                let position = machine.pc().position();
                machine.stack_mut().push((position - 1).into()); // PC increment for opcode is always an u8.
            },

            Opcode::MSIZE => {
                let active_len = machine.memory().active_len();
                machine.stack_mut().push(active_len.into());
            },

            Opcode::GAS => {
                let gas: U256 = machine.transaction().gas_limit().into();
                machine.stack_mut().push(gas);
            },

            Opcode::JUMPDEST => (), // This operation has no effect on machine state during execution.

            Opcode::PUSH(v) => {
                let val = machine.pc_mut().read(v);
                machine.stack_mut().push(val);
            },

            Opcode::DUP(v) => {
                let val = machine.stack().peek(v - 1);
                machine.stack_mut().push(val);
            },

            Opcode::SWAP(v) => {
                let val1 = machine.stack().peek(0);
                let val2 = machine.stack().peek(v);
                machine.stack_mut().set(0, val2);
                machine.stack_mut().set(v, val1);
            },

            // TODO: Implement log entries LOG0, LOG1, LOG2, LOG3, LOG4

            // TODO: Implement system operations 0xf0 to 0xff

            _ => {
                unimplemented!();
            }
        }
    }
}
<commit_msg>Problem: SLOAD and SSTORE is not implemented Solution: Implement them!<commit_after>use utils::u256::U256;
use utils::gas::Gas;
use super::Opcode;
use vm::{Machine, Memory, Stack, PC};
use account::Storage;
use transaction::Transaction;

use std::ops::{Add, Sub, Not, Mul, Div, Shr, Shl, BitAnd, BitOr, BitXor};
use crypto::sha3::Sha3;
use crypto::digest::Digest;

fn signed_abs(v: U256) -> U256 {
    let negative: U256 = U256::one() << 256;

    if v >= negative {
        !v + 1.into()
    } else {
        v
    }
}

macro_rules! op2 {
    ( $machine:expr, $op:ident ) => ({
        let op1 = $machine.stack_mut().pop();
        let op2 = $machine.stack_mut().pop();
        $machine.stack_mut().push(op1.$op(op2));
    })
}

macro_rules! op2_ref {
    ( $machine:expr, $op:ident ) => ({
        let op1 = $machine.stack_mut().pop();
        let op2 = $machine.stack_mut().pop();
        $machine.stack_mut().push(op1.$op(&op2).into());
    })
}

impl Opcode {
    pub fn run<M: Machine>(&self, machine: &mut M) {
        let opcode = self.clone();

        match opcode {
            Opcode::STOP => {
                machine.pc_mut().stop();
            },

            Opcode::ADD => op2!(machine, add),
            Opcode::MUL => op2!(machine, mul),
            Opcode::SUB => op2!(machine, sub),

            Opcode::DIV => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(op1 / op2);
                }
            },

            Opcode::SDIV => {
                // This is signed division. So the U256 would need to
                // be treated as signed two's complement. We currently
                // convert it to both positive, and then deal with the
                // sign afterwards...

                let negative: U256 = U256::one() << 256;
                // This value is also -2^255 in two's complement.
                let max: U256 = U256::max_value();
                // This value is also -1 in two's complement.

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else if op1 == negative && op2 == max {
                    machine.stack_mut().push(negative);
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = op1 / op2;

                    if (op1 < negative && op2 < negative) || (op1 >= negative && op2 >= negative) {
                        machine.stack_mut().push(r);
                    } else {
                        let sr = !r + 1.into();
                        machine.stack_mut().push(sr);
                    }
                }
            },

            Opcode::MOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(op1 - (op1 / op2) * op2);
                }
            },

            Opcode::SMOD => {
                let negative: U256 = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op2 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    let aop1 = signed_abs(op1);
                    let aop2 = signed_abs(op2);
                    let r = aop1 - (aop1 / aop2) * aop2;
                    if op1 < negative && op2 < negative {
                        machine.stack_mut().push(r);
                    } else if op1 >= negative && op2 < negative {
                        machine.stack_mut().push(!(op1 + r) + 1.into());
                    } else if op1 < negative && op2 >= negative {
                        machine.stack_mut().push(op1 + r);
                    } else if op1 >= negative && op2 >= negative {
                        machine.stack_mut().push(!r + 1.into());
                    }
                }
            },

            Opcode::ADDMOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                let op3 = machine.stack_mut().pop();

                if op3 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    // TODO: Handle the case where op1 + op2 > 2^256
                    let v = op1 + op2;
                    machine.stack_mut().push(v - (v / op3) * op3);
                }
            },

            Opcode::MULMOD => {
                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();
                let op3 = machine.stack_mut().pop();

                if op3 == 0.into() {
                    machine.stack_mut().push(0.into());
                } else {
                    // TODO: Handle the case where op1 * op2 > 2^256
                    let v = op1 * op2;
                    machine.stack_mut().push(v - (v / op3) * op3);
                }
            },

            Opcode::EXP => {
                let op1 = machine.stack_mut().pop();
                let mut op2 = machine.stack_mut().pop();
                let mut r: U256 = 1.into();

                while op2 != 0.into() {
                    r = r * op1;
                    op2 = op2 - 1.into();
                }
                machine.stack_mut().push(r);
            },

            Opcode::SIGNEXTEND => {
                // TODO: Check this confines with the yello paper

                let mut op1 = machine.stack_mut().pop();
                let mut op2 = machine.stack_mut().pop();

                let mut negative: U256 = 1.into();
                let mut s = 0;
                while op2 != 0.into() {
                    negative = U256::one() << s;
                    s = s + 1;
                    op2 = op2 - 1.into();
                }

                if op1 >= negative {
                    while s <= 256 {
                        op1 = op1 + (U256::one() << s);
                        s = s + 1;
                    }
                    machine.stack_mut().push(op1);
                } else {
                    machine.stack_mut().push(op1);
                }
            },

            Opcode::LT => op2_ref!(machine, lt),
            Opcode::GT => op2_ref!(machine, gt),

            Opcode::SLT => {
                let negative = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op1 < negative && op2 < negative {
                    if op1 < op2 {
                        machine.stack_mut().push(1.into());
                    } else {
                        machine.stack_mut().push(0.into());
                    }
                } else if op2 >= negative && op2 >= negative {
                    if op1 < op2 {
                        machine.stack_mut().push(0.into());
                    } else {
                        machine.stack_mut().push(1.into());
                    }
                } else if op1 < negative && op2 >= negative {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push(1.into());
                }
            },

            Opcode::SGT => {
                let negative = U256::one() << 256;

                let op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                if op1 < negative && op2 < negative {
                    if op1 < op2 {
                        machine.stack_mut().push(0.into());
                    } else {
                        machine.stack_mut().push(1.into());
                    }
                } else if op2 >= negative && op2 >= negative {
                    if op1 < op2 {
                        machine.stack_mut().push(1.into());
                    } else {
                        machine.stack_mut().push(0.into());
                    }
                } else if op1 < negative && op2 >= negative {
                    machine.stack_mut().push(1.into());
                } else {
                    machine.stack_mut().push(0.into());
                }
            },

            Opcode::EQ => op2_ref!(machine, eq),

            Opcode::ISZERO => {
                let op1 = machine.stack_mut().pop();

                if op1 == 0.into() {
                    machine.stack_mut().push(1.into());
                } else {
                    machine.stack_mut().push(0.into());
                }
            },

            Opcode::AND => op2!(machine, bitand),
            Opcode::OR => op2!(machine, bitor),
            Opcode::XOR => op2!(machine, bitxor),

            Opcode::NOT => {
                let op1 = machine.stack_mut().pop();

                machine.stack_mut().push(!op1);
            },

            Opcode::BYTE => {
                let op1 = machine.stack_mut().pop();
                let op2: usize = machine.stack_mut().pop().into(); // 256 / 8
                let mark: U256 = 0xff.into();

                if op2 >= 256 / 8 {
                    machine.stack_mut().push(0.into());
                } else {
                    machine.stack_mut().push((op1 >> (op2 * 8)) & mark);
                }
            },

            Opcode::SHA3 => {
                let mut op1 = machine.stack_mut().pop();
                let op2 = machine.stack_mut().pop();

                let mut r: [u8; 32] = [0u8; 32];
                let mut sha3 = Sha3::keccak256();

                while op1 != op2 - 1.into() {
                    let val = machine.memory_mut().read(op1);
                    sha3.input(val.as_ref());
                    op1 = op1 + 1.into();
                }
                sha3.result(&mut r);
                machine.stack_mut().push(U256::from(r.as_ref()))
            },

            // TODO: implement opcode 0x21 to 0x4f

            Opcode::POP => {
                machine.stack_mut().pop();
            },

            Opcode::MLOAD => {
                let op1 = machine.stack_mut().pop();
                let val = machine.memory_mut().read(op1);
                // u_i update is automatically handled by Memory.
                machine.stack_mut().push(val);
            },

            Opcode::MSTORE => {
                let op1 = machine.stack_mut().pop(); // Index
                let op2 = machine.stack_mut().pop(); // Data
                // u_i update is automatically handled by Memory.
                machine.memory_mut().write(op1, op2);
            },

            Opcode::SLOAD => {
                let op1 = machine.stack_mut().pop();
                let val = machine.storage_mut().read(op1);
                machine.stack_mut().push(val);
            },

            Opcode::SSTORE => {
                let op1 = machine.stack_mut().pop(); // Index
                let op2 = machine.stack_mut().pop(); // Data
                machine.storage_mut().write(op1, op2);
            }

            Opcode::JUMP => {
                let op1_u: u64 = machine.stack_mut().pop().into();
                machine.pc_mut().jump(op1_u as usize);
            },

            Opcode::JUMPI => {
                let op1_u: u64 = machine.stack_mut().pop().into();
                let op2 = machine.stack_mut().pop();

                if op2 != 0.into() {
                    machine.pc_mut().jump(op1_u as usize);
                }
            },

            Opcode::PC => {
                let position = machine.pc().position();
                machine.stack_mut().push((position - 1).into()); // PC increment for opcode is always an u8.
            },

            Opcode::MSIZE => {
                let active_len = machine.memory().active_len();
                machine.stack_mut().push(active_len.into());
            },

            Opcode::GAS => {
                let gas: U256 = machine.transaction().gas_limit().into();
                machine.stack_mut().push(gas);
            },

            Opcode::JUMPDEST => (), // This operation has no effect on machine state during execution.

            Opcode::PUSH(v) => {
                let val = machine.pc_mut().read(v);
                machine.stack_mut().push(val);
            },

            Opcode::DUP(v) => {
                let val = machine.stack().peek(v - 1);
                machine.stack_mut().push(val);
            },

            Opcode::SWAP(v) => {
                let val1 = machine.stack().peek(0);
                let val2 = machine.stack().peek(v);
                machine.stack_mut().set(0, val2);
                machine.stack_mut().set(v, val1);
            },

            // TODO: Implement log entries LOG0, LOG1, LOG2, LOG3, LOG4

            // TODO: Implement system operations 0xf0 to 0xff

            _ => {
                unimplemented!();
            }
        }
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
#![feature(link_cfg)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(unwind_attributes)]
#![feature(static_nobundle)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]

cfg_if::cfg_if! {
    if #[cfg(target_env = "msvc")] {
        // Windows MSVC no extra unwinder support needed
    } else if #[cfg(any(
        target_os = "l4re",
        target_os = "none",
    ))] {
        // These "unix" family members do not have unwinder.
        // Note this also matches x86_64-linux-kernel.
    } else if #[cfg(any(
        unix,
        windows,
        target_os = "psp",
        target_os = "cloudabi",
        all(target_vendor = "fortanix", target_env = "sgx"),
    ))] {
        mod libunwind;
        pub use libunwind::*;
    } else {
        // no unwinder on the system!
        // - wasm32 (not emscripten, which is "unix" family)
        // - os=none ("bare metal" targets)
        // - os=hermit
        // - os=uefi
        // - os=cuda
        // - nvptx64-nvidia-cuda
        // - Any new targets not listed above.
    }
}

#[cfg(target_env = "musl")]
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "llvm-libunwind")))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(target_os = "redox")]
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
#[link(name = "unwind", kind = "static-nobundle")]
extern "C" {}
<commit_msg>Add comment explaining why libunwind doesn't need to link libgcc_eh<commit_after>#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
#![feature(link_cfg)]
#![feature(nll)]
#![feature(staged_api)]
#![feature(unwind_attributes)]
#![feature(static_nobundle)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]

cfg_if::cfg_if! {
    if #[cfg(target_env = "msvc")] {
        // Windows MSVC no extra unwinder support needed
    } else if #[cfg(any(
        target_os = "l4re",
        target_os = "none",
    ))] {
        // These "unix" family members do not have unwinder.
        // Note this also matches x86_64-linux-kernel.
    } else if #[cfg(any(
        unix,
        windows,
        target_os = "psp",
        target_os = "cloudabi",
        all(target_vendor = "fortanix", target_env = "sgx"),
    ))] {
        mod libunwind;
        pub use libunwind::*;
    } else {
        // no unwinder on the system!
        // - wasm32 (not emscripten, which is "unix" family)
        // - os=none ("bare metal" targets)
        // - os=hermit
        // - os=uefi
        // - os=cuda
        // - nvptx64-nvidia-cuda
        // - Any new targets not listed above.
    }
}

#[cfg(target_env = "musl")]
#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

// When building with crt-static, we get `gcc_eh` from the `libc` crate, since
// glibc needs it, and needs it listed later on the linker command line. We
// don't want to duplicate it here.
#[cfg(all(target_os = "linux", target_env = "gnu", not(feature = "llvm-libunwind")))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(target_os = "redox")]
#[link(name = "gcc_eh", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
extern "C" {}

#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
#[link(name = "unwind", kind = "static-nobundle")]
extern "C" {}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! A symbol reader reads one symbol at a time from a source
//!

use std::slice::Iter;
use std::io::Read;
use std::io::Bytes;
use std::str::Chars;
use std::marker::PhantomData;

///
/// A symbol reader reads one symbol at a time from a source
///
pub trait SymbolReader<Symbol> {
    ///
    /// Reads the next symbol from this reader
    ///
    fn next_symbol(&mut self) -> Option<Symbol>;
}

///
/// Trait that can be implemented by things that can construct a symbol reader
///
pub trait SymbolSource<'a, Symbol> {
    /// The type of symbol reader that will be generated by this call
    type SymbolReader: SymbolReader<Symbol>+'a;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader;
}

impl<'a, Symbol: Clone+'a> SymbolSource<'a, Symbol> for &'a Vec<Symbol> {
    type SymbolReader = Iter<'a, Symbol>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.iter()
    }
}

impl<'a, Symbol: Clone+'a> SymbolReader<Symbol> for Iter<'a, Symbol> {
    fn next_symbol(&mut self) -> Option<Symbol> {
        if let Some(sym) = self.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

// Can read from streams

//
// TODO: implementing SymbolSource for Read would be nice
// It's just a matter of calling bytes() on the appropriate type, but Rust's type system is simultaneously too clever and not clever enough
// to allow that in any sensible way. You can't do it an an arbitrary Read because the Bytes object is not sized without knowing its real
// type; I couldn't figure out a trick using the Self type to get around that, though those do work sometimes.
// `impl<X: Read> SymbolReader for X` sounds like a nice idea but Rust thinks X can be anything and won't allow any other implementations
// of the interface, which makes that useless too.
// Screwing around with lifetimes and references like below seems like it should work, but Rust doesn't seem to see the implementations on
// actual streams.
//

/*
impl<'a> SymbolSource<'a, u8> for &'a mut Read {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}

impl<'a> SymbolSource<'a, u8> for &'a mut BufRead {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}
*/

///
/// The ByteSymbolReader turns a `std::io::Bytes` object into a symbol reader
///
pub struct ByteSymbolReader<Reader: Read> {
    bytes: Bytes<Reader>
}

impl<Reader: Read> ByteSymbolReader<Reader> {
    pub fn new(bytes: Bytes<Reader>) -> ByteSymbolReader<Reader> {
        ByteSymbolReader { bytes: bytes }
    }

    pub fn from(reader: Reader) -> ByteSymbolReader<Reader> {
        Self::new(reader.bytes())
    }
}

impl<Reader: Read> SymbolReader<u8> for ByteSymbolReader<Reader> {
    fn next_symbol(&mut self) -> Option<u8> {
        if let Some(Ok(sym)) = self.bytes.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

//
// Can read from strings
//
impl<'a> SymbolSource<'a, char> for &'a str {
    type SymbolReader = Chars<'a>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.chars()
    }
}

impl<'a> SymbolReader<char> for Chars<'a> {
    fn next_symbol(&mut self) -> Option<char> {
        self.next()
    }
}

///
/// Converts symbol streams to vectors
///
pub trait ReaderToVector<Symbol> {
    /// Reads every symbol in this object and returns a vector
    fn to_vec(&mut self) -> Vec<Symbol>;
}

impl<Symbol, Reader: SymbolReader<Symbol>> ReaderToVector<Symbol> for Reader {
    #[inline]
    fn to_vec(&mut self) -> Vec<Symbol> {
        let mut result = vec![];

        while let Some(symbol) = self.next_symbol() {
            result.push(symbol);
        }

        result
    }
}

///
/// A symbol stream that performs mapping of symbols from a source stream
///
pub struct MappedStream<'a, InputSymbol, MapFunction, Reader>
where Reader: SymbolReader<InputSymbol>+'a {
    /// The source stream
    source_stream: &'a mut Reader,

    /// A function used to map a symbol from the source stream to a symbol in the output stream
    mapping_function: MapFunction,

    // Can't see how to eliminate the input symbol reference due to rust's type system. InputSymbol is used by source_stream, but rust can't see that
    #[allow(dead_code)]
    phantom: PhantomData<InputSymbol>
}

///
/// Provides a way to map symbol streams to streams of other types
///
pub trait MapSymbolReader<Symbol> : SymbolReader<Symbol>+Sized {
    /// Maps symbols in this stream to symbols in a new stream
    fn map_symbols<'a, OutputSymbol, MapFunction>(&'a mut self, mapping_function: MapFunction) -> MappedStream<'a, Symbol, MapFunction, Self>
    where MapFunction: FnMut(Symbol) -> OutputSymbol;
}

impl<Symbol, Reader: SymbolReader<Symbol>> MapSymbolReader<Symbol> for Reader {
    fn map_symbols<'a, OutputSymbol, MapFunction>(&'a mut self, mapping_function: MapFunction) -> MappedStream<'a, Symbol, MapFunction, Self>
    where MapFunction: FnMut(Symbol) -> OutputSymbol {
        MappedStream {
            source_stream:    self,
            mapping_function: mapping_function,
            phantom:          PhantomData
        }
    }
}

impl<'a, InputSymbol, OutputSymbol, MapFunction, Reader: SymbolReader<InputSymbol>+'a> SymbolReader<OutputSymbol> for MappedStream<'a, InputSymbol, MapFunction, Reader>
where MapFunction: FnMut(InputSymbol) -> OutputSymbol {
    fn next_symbol(&mut self) -> Option<OutputSymbol> {
        if let Some(input_symbol) = self.source_stream.next_symbol() {
            Some((self.mapping_function)(input_symbol))
        } else {
            None
        }
    }
}

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

    #[test]
    fn can_read_from_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_convert_to_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();
        let result      = reader.to_vec();

        assert!(result == vec![1, 2, 3]);
    }

    #[test]
    fn can_map_stream() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();
        let result      = reader.map_symbols(|sym| sym+1).to_vec();

        assert!(result == vec![2, 3, 4]);
    }

    #[test]
    fn can_read_from_bytes_reader() {
        let array: [u8; 3] = [1, 2, 3];
        let slice = &array[..];
        let mut reader = ByteSymbolReader::from(slice);

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_read_from_string_reader() {
        let mut reader = "abc".read_symbols();

        assert!(reader.next_symbol() == Some('a'));
        assert!(reader.next_symbol() == Some('b'));
        assert!(reader.next_symbol() == Some('c'));
        assert!(reader.next_symbol() == None);
    }
}
<commit_msg>Add comment about why there’s phantom data<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! A symbol reader reads one symbol at a time from a source
//!

use std::slice::Iter;
use std::io::Read;
use std::io::Bytes;
use std::str::Chars;
use std::marker::PhantomData;

///
/// A symbol reader reads one symbol at a time from a source
///
pub trait SymbolReader<Symbol> {
    ///
    /// Reads the next symbol from this reader
    ///
    fn next_symbol(&mut self) -> Option<Symbol>;
}

///
/// Trait that can be implemented by things that can construct a symbol reader
///
pub trait SymbolSource<'a, Symbol> {
    /// The type of symbol reader that will be generated by this call
    type SymbolReader: SymbolReader<Symbol>+'a;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader;
}

impl<'a, Symbol: Clone+'a> SymbolSource<'a, Symbol> for &'a Vec<Symbol> {
    type SymbolReader = Iter<'a, Symbol>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.iter()
    }
}

impl<'a, Symbol: Clone+'a> SymbolReader<Symbol> for Iter<'a, Symbol> {
    fn next_symbol(&mut self) -> Option<Symbol> {
        if let Some(sym) = self.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

// Can read from streams

//
// TODO: implementing SymbolSource for Read would be nice
// It's just a matter of calling bytes() on the appropriate type, but Rust's type system is simultaneously too clever and not clever enough
// to allow that in any sensible way. You can't do it an an arbitrary Read because the Bytes object is not sized without knowing its real
// type; I couldn't figure out a trick using the Self type to get around that, though those do work sometimes.
// `impl<X: Read> SymbolReader for X` sounds like a nice idea but Rust thinks X can be anything and won't allow any other implementations
// of the interface, which makes that useless too.
// Screwing around with lifetimes and references like below seems like it should work, but Rust doesn't seem to see the implementations on
// actual streams.
//

/*
impl<'a> SymbolSource<'a, u8> for &'a mut Read {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}

impl<'a> SymbolSource<'a, u8> for &'a mut BufRead {
    type SymbolReader = ByteSymbolReader<Self>;

    fn read_symbols(self) -> Self::SymbolReader {
        ByteSymbolReader::new(self.bytes())
    }
}
*/

///
/// The ByteSymbolReader turns a `std::io::Bytes` object into a symbol reader
///
pub struct ByteSymbolReader<Reader: Read> {
    bytes: Bytes<Reader>
}

impl<Reader: Read> ByteSymbolReader<Reader> {
    pub fn new(bytes: Bytes<Reader>) -> ByteSymbolReader<Reader> {
        ByteSymbolReader { bytes: bytes }
    }

    pub fn from(reader: Reader) -> ByteSymbolReader<Reader> {
        Self::new(reader.bytes())
    }
}

impl<Reader: Read> SymbolReader<u8> for ByteSymbolReader<Reader> {
    fn next_symbol(&mut self) -> Option<u8> {
        if let Some(Ok(sym)) = self.bytes.next() {
            Some(sym.clone())
        } else {
            None
        }
    }
}

//
// Can read from strings
//
impl<'a> SymbolSource<'a, char> for &'a str {
    type SymbolReader = Chars<'a>;

    fn read_symbols(self) -> Self::SymbolReader {
        self.chars()
    }
}

impl<'a> SymbolReader<char> for Chars<'a> {
    fn next_symbol(&mut self) -> Option<char> {
        self.next()
    }
}

///
/// Converts symbol streams to vectors
///
pub trait ReaderToVector<Symbol> {
    /// Reads every symbol in this object and returns a vector
    fn to_vec(&mut self) -> Vec<Symbol>;
}

impl<Symbol, Reader: SymbolReader<Symbol>> ReaderToVector<Symbol> for Reader {
    #[inline]
    fn to_vec(&mut self) -> Vec<Symbol> {
        let mut result = vec![];

        while let Some(symbol) = self.next_symbol() {
            result.push(symbol);
        }

        result
    }
}

///
/// A symbol stream that performs mapping of symbols from a source stream
///
pub struct MappedStream<'a, InputSymbol, MapFunction, Reader>
where Reader: SymbolReader<InputSymbol>+'a {
    /// The source stream
    source_stream: &'a mut Reader,

    /// A function used to map a symbol from the source stream to a symbol in the output stream
    mapping_function: MapFunction,

    /// Can't see how to eliminate the input symbol reference due to rust's type system. InputSymbol is used by source_stream, but rust can't see that
    #[allow(dead_code)]
    phantom: PhantomData<InputSymbol>
}

///
/// Provides a way to map symbol streams to streams of other types
///
pub trait MapSymbolReader<Symbol> : SymbolReader<Symbol>+Sized {
    /// Maps symbols in this stream to symbols in a new stream
    fn map_symbols<'a, OutputSymbol, MapFunction>(&'a mut self, mapping_function: MapFunction) -> MappedStream<'a, Symbol, MapFunction, Self>
    where MapFunction: FnMut(Symbol) -> OutputSymbol;
}

impl<Symbol, Reader: SymbolReader<Symbol>> MapSymbolReader<Symbol> for Reader {
    fn map_symbols<'a, OutputSymbol, MapFunction>(&'a mut self, mapping_function: MapFunction) -> MappedStream<'a, Symbol, MapFunction, Self>
    where MapFunction: FnMut(Symbol) -> OutputSymbol {
        MappedStream {
            source_stream:    self,
            mapping_function: mapping_function,
            phantom:          PhantomData
        }
    }
}

impl<'a, InputSymbol, OutputSymbol, MapFunction, Reader: SymbolReader<InputSymbol>+'a> SymbolReader<OutputSymbol> for MappedStream<'a, InputSymbol, MapFunction, Reader>
where MapFunction: FnMut(InputSymbol) -> OutputSymbol {
    // TODO: would like to eliminate InputSymbol as phantom data from the structure
    // This means removing the constraint on Reader. That doesn't work because rust then thinks InputSymbol is unconstrained here,
    // even though it's constrained by the function type, the reader type *and* the structure type

    fn next_symbol(&mut self) -> Option<OutputSymbol> {
        if let Some(input_symbol) = self.source_stream.next_symbol() {
            Some((self.mapping_function)(input_symbol))
        } else {
            None
        }
    }
}

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

    #[test]
    fn can_read_from_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_convert_to_vec() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();
        let result      = reader.to_vec();

        assert!(result == vec![1, 2, 3]);
    }

    #[test]
    fn can_map_stream() {
        let source      = vec![1, 2, 3];
        let mut reader  = source.read_symbols();
        let result      = reader.map_symbols(|sym| sym+1).to_vec();

        assert!(result == vec![2, 3, 4]);
    }

    #[test]
    fn can_read_from_bytes_reader() {
        let array: [u8; 3] = [1, 2, 3];
        let slice = &array[..];
        let mut reader = ByteSymbolReader::from(slice);

        assert!(reader.next_symbol() == Some(1));
        assert!(reader.next_symbol() == Some(2));
        assert!(reader.next_symbol() == Some(3));
        assert!(reader.next_symbol() == None);
    }

    #[test]
    fn can_read_from_string_reader() {
        let mut reader = "abc".read_symbols();

        assert!(reader.next_symbol() == Some('a'));
        assert!(reader.next_symbol() == Some('b'));
        assert!(reader.next_symbol() == Some('c'));
        assert!(reader.next_symbol() == None);
    }
}
<|endoftext|>


<commit_before>extern crate azure_sdk_for_rust;

extern crate futures;
extern crate tokio_core;
extern crate tokio;
extern crate hyper;
extern crate hyper_tls;
extern crate chrono;

use std::error::Error;

use tokio_core::reactor::Core;

use azure_sdk_for_rust::azure::cosmos::authorization_token::{AuthorizationToken, TokenType};
use azure_sdk_for_rust::azure::cosmos::client::Client;
use azure_sdk_for_rust::azure::cosmos::list_documents::LIST_DOCUMENTS_OPTIONS_DEFAULT;
use azure_sdk_for_rust::azure::cosmos::get_document::GET_DOCUMENT_OPTIONS_DEFAULT;
use azure_sdk_for_rust::azure::cosmos::request_response::{ListDocumentsResponse,
                                                          GetDocumentResponse};

#[macro_use]
extern crate serde_derive;

// Now we create the same struct twice. The second
// will be used by the 'get' methods. There must not
// be references: the struct must own all the data. This
// is required in order to satisfy DeserializeOwned.
#[derive(Serialize, Deserialize, Debug)]
struct MySampleStruct<'a> {
    id: &'a str,
    a_string: &'a str,
    a_number: u64,
    a_timestamp: i64,
}

// Shadow struct. See above. Of course
// you do not need both if your starting
// struct owns all its data.
#[derive(Serialize, Deserialize, Debug)]
struct MySampleStructOwned {
    id: String,
    a_string: String,
    a_number: u64,
    a_timestamp: i64,
}

fn main() {
    code().unwrap();
}

fn code() -> Result<(), Box<Error>> {
    let database_name = std::env::args().nth(1).expect(
        "please specify database name as first command line parameter",
    );
    let collection_name = std::env::args().nth(2).expect(
        "please specify collection name as second command line parameter",
    );

    let master_key = std::env::var("COSMOS_MASTER_KEY")
        .expect("Set env variable COSMOS_MASTER_KEY first!");
    let account = std::env::var("COSMOS_ACCOUNT").expect("Set env variable COSMOS_ACCOUNT first!");

    let authorization_token = AuthorizationToken::new(account, TokenType::Master, master_key)?;

    let mut core = Core::new()?;

    let client = Client::new(&core.handle(), authorization_token)?;

    for i in 0..5 {
        let doc = MySampleStruct {
            id: &format!("unique_id{}", i),
            a_string: "Something here",
            a_number: i,
            a_timestamp: chrono::Utc::now().timestamp(),
        };

        // let's add an entity. we ignore the errors at this point and just
        // notify the user.
        match core.run(
            client.create_document_as_entity(&database_name, &collection_name, false, None, &doc),
        ) {
            Ok(_) => {
                println!("entity added");
            }
            Err(error) => {
                println!("entity add failed (maybe already there?) {:?}", error);
            }
        };
    }

    // let's get 3 entries at a time
    let mut ldo = LIST_DOCUMENTS_OPTIONS_DEFAULT.clone();
    ldo.max_item_count = Some(3);

    let response: ListDocumentsResponse<MySampleStructOwned> = core.run(
        client.list_documents(&database_name, &collection_name, &ldo),
    ).unwrap();

    assert_eq!(response.documents.len(), 3);
    println!("response == {:?}", response);

    // we inserted 5 documents and retrieved the first 3.
    // continuation_token must be present
    assert_eq!(
        response.additional_headers.continuation_token.is_some(),
        true
    );
    if let Some(ct) = response.additional_headers.continuation_token {
        println!("ct == {}", ct);

        let mut ldo = LIST_DOCUMENTS_OPTIONS_DEFAULT.clone();
        ldo.continuation_token = Some(&ct);

        let response: ListDocumentsResponse<MySampleStructOwned> = core.run(
            client.list_documents(&database_name, &collection_name, &ldo),
        ).unwrap();

        assert_eq!(response.documents.len(), 2);
        println!("response == {:?}", response);

        // we got the last 2 entries. Now continuation_token
        // must be clear
        assert_eq!(
            response.additional_headers.continuation_token.is_some(),
            false
        );

        let gdo = GET_DOCUMENT_OPTIONS_DEFAULT.clone();
        let id = format!("unique_id{}", 3);

        let response: GetDocumentResponse<MySampleStructOwned> = core.run(
            client.get_document(&database_name, &collection_name, &id, &gdo),
        ).unwrap();

        assert_eq!(response.document.is_some(), true);
        println!("response == {:?}", response);

        // This id should not be found. We expect None as result
        let id = format!("unique_id{}", 100);

        let response: GetDocumentResponse<MySampleStructOwned> = core.run(
            client.get_document(&database_name, &collection_name, &id, &gdo),
        ).unwrap();

        assert_eq!(response.document.is_some(), false);
        println!("response == {:?}", response);
    }

    Ok(())
}
<commit_msg>corrected typo in comment<commit_after>extern crate azure_sdk_for_rust;

extern crate futures;
extern crate tokio_core;
extern crate tokio;
extern crate hyper;
extern crate hyper_tls;
extern crate chrono;

use std::error::Error;

use tokio_core::reactor::Core;

use azure_sdk_for_rust::azure::cosmos::authorization_token::{AuthorizationToken, TokenType};
use azure_sdk_for_rust::azure::cosmos::client::Client;
use azure_sdk_for_rust::azure::cosmos::list_documents::LIST_DOCUMENTS_OPTIONS_DEFAULT;
use azure_sdk_for_rust::azure::cosmos::get_document::GET_DOCUMENT_OPTIONS_DEFAULT;
use azure_sdk_for_rust::azure::cosmos::request_response::{ListDocumentsResponse,
                                                          GetDocumentResponse};

#[macro_use]
extern crate serde_derive;

// Now we create the same struct twice. The second
// will be used by the 'get' methods. There must not
// be references: the struct must own all the data. This
// is required in order to satisfy DeserializeOwned.
#[derive(Serialize, Deserialize, Debug)]
struct MySampleStruct<'a> {
    id: &'a str,
    a_string: &'a str,
    a_number: u64,
    a_timestamp: i64,
}

// Shadow struct. See above. Of course
// you do not need both if your starting
// struct owns all its data.
#[derive(Serialize, Deserialize, Debug)]
struct MySampleStructOwned {
    id: String,
    a_string: String,
    a_number: u64,
    a_timestamp: i64,
}

fn main() {
    code().unwrap();
}

fn code() -> Result<(), Box<Error>> {
    let database_name = std::env::args().nth(1).expect(
        "please specify database name as first command line parameter",
    );
    let collection_name = std::env::args().nth(2).expect(
        "please specify collection name as second command line parameter",
    );

    let master_key = std::env::var("COSMOS_MASTER_KEY")
        .expect("Set env variable COSMOS_MASTER_KEY first!");
    let account = std::env::var("COSMOS_ACCOUNT").expect("Set env variable COSMOS_ACCOUNT first!");

    let authorization_token = AuthorizationToken::new(account, TokenType::Master, master_key)?;

    let mut core = Core::new()?;

    let client = Client::new(&core.handle(), authorization_token)?;

    for i in 0..5 {
        let doc = MySampleStruct {
            id: &format!("unique_id{}", i),
            a_string: "Something here",
            a_number: i,
            a_timestamp: chrono::Utc::now().timestamp(),
        };

        // let's add an entity. we ignore the errors at this point and just
        // notify the user.
        match core.run(
            client.create_document_as_entity(&database_name, &collection_name, false, None, &doc),
        ) {
            Ok(_) => {
                println!("entity added");
            }
            Err(error) => {
                println!("entity add failed (maybe already there?) {:?}", error);
            }
        };
    }

    // let's get 3 entries at a time
    let mut ldo = LIST_DOCUMENTS_OPTIONS_DEFAULT.clone();
    ldo.max_item_count = Some(3);

    let response: ListDocumentsResponse<MySampleStructOwned> = core.run(
        client.list_documents(&database_name, &collection_name, &ldo),
    ).unwrap();

    assert_eq!(response.documents.len(), 3);
    println!("response == {:?}", response);

    // we inserted 5 documents and retrieved the first 3.
    // continuation_token must be present
    assert_eq!(
        response.additional_headers.continuation_token.is_some(),
        true
    );
    if let Some(ct) = response.additional_headers.continuation_token {
        println!("ct == {}", ct);

        let mut ldo = LIST_DOCUMENTS_OPTIONS_DEFAULT.clone();
        ldo.continuation_token = Some(&ct);

        let response: ListDocumentsResponse<MySampleStructOwned> = core.run(
            client.list_documents(&database_name, &collection_name, &ldo),
        ).unwrap();

        assert_eq!(response.documents.len(), 2);
        println!("response == {:?}", response);

        // we got the last 2 entries. Now continuation_token
        // must be absent
        assert_eq!(
            response.additional_headers.continuation_token.is_some(),
            false
        );

        let gdo = GET_DOCUMENT_OPTIONS_DEFAULT.clone();
        let id = format!("unique_id{}", 3);

        let response: GetDocumentResponse<MySampleStructOwned> = core.run(
            client.get_document(&database_name, &collection_name, &id, &gdo),
        ).unwrap();

        assert_eq!(response.document.is_some(), true);
        println!("response == {:?}", response);

        // This id should not be found. We expect None as result
        let id = format!("unique_id{}", 100);

        let response: GetDocumentResponse<MySampleStructOwned> = core.run(
            client.get_document(&database_name, &collection_name, &id, &gdo),
        ).unwrap();

        assert_eq!(response.document.is_some(), false);
        println!("response == {:?}", response);
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Methods for converting shapes into triangles.

use std;
use {
    Image,
    Matrix2d,
    Rectangle,
};
use interpolation::{lerp};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * std::f64::consts::PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: [f32, ..4]) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}

<commit_msg>Started on `with_round_border_line_tri_list_xy_f32_rgba_f32`<commit_after>//! Methods for converting shapes into triangles.

use std;
use {
    Image,
    Line,
    Matrix2d,
    Rectangle,
    RoundBorder,
};
use interpolation::{lerp};

#[inline(always)]
fn tx(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[0] * x + m[1] * y + m[2]) as f32
}

#[inline(always)]
fn ty(m: &Matrix2d, x: f64, y: f64) -> f32 {
    (m[3] * x + m[4] * y + m[5]) as f32
}

/// Streams tweened polygons using linear interpolation.
#[inline(always)]
pub fn with_lerp_polygons_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygons: &[&[f64]],
    tween_factor: f64,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let poly_len = polygons.len() as f64;
    // Map to interval between 0 and 1.
    let tw = tween_factor % 1.0;
    // Map negative values to positive.
    let tw = if tw < 0.0 { tw + 1.0 } else { tw };
    // Map to frame.
    let tw = tw * poly_len;
    // Get the current frame.
    let frame = tw as uint;
    // Get the next frame.
    let next_frame = (frame + 1) % polygons.len();
    let p0 = polygons[frame];
    let p1 = polygons[next_frame];
    // Get factor between frames.
    let tw = tw - frame as f64;
    let n = polygons[0].len();
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 2;
        let (x0, y0) = (p0[j], p0[j+1]);
        let (x1, y1) = (p1[j], p1[j+1]);
        Some([lerp(&x0, &x1, &tw), lerp(&y0, &y1, &tw)])
    }, color, f);
}

/// Streams an ellipse specified by a resolution.
#[inline(always)]
pub fn with_ellipse_tri_list_xy_f32_rgba_f32(
    resolution: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (cw, ch) = (0.5 * w, 0.5 * h);
    let (cx, cy) = (x + cw, y + ch);
    let n = resolution;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let angle = i as f64 / n as f64 * std::f64::consts::PI_2;
        i += 1;
        Some([cx + angle.cos() * cw, cy + angle.sin() * ch])
    }, color, f);
}

/// Streams a round border line.
#[inline(always)]
pub fn with_round_border_line_tri_list_xy_f32_rgba_f32(
    _resolution_corner: uint,
    _m: &Matrix2d,
    _line: &Line,
    _round_border: &RoundBorder,
    _color: [f32, ..4],
    _f: |vertices: &[f32], colors: &[f32]|) {

    /*
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = round_border[0];
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
    */
}

/// Streams a round rectangle.
#[inline(always)]
pub fn with_round_rectangle_tri_list_xy_f32_rgba_f32(
    resolution_corner: uint,
    m: &Matrix2d,
    rect: &Rectangle,
    round_radius: &f64,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let radius = *round_radius;
    let n = resolution_corner * 4 + 4;
    let mut i = 0u;
    stream_polygon_tri_list_xy_f32_rgba_f32(m, || {
        if i >= n { return None; }

        let j = i;
        i += 1;
        match j {
            j if j >= resolution_corner * 3 => {
                let angle = j as f64 / (n - 3) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 2 => {
                let angle = j as f64 / (n - 2) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j if j >= resolution_corner * 1 => {
                let angle = j as f64 / (n - 1) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
            j => {
                let angle = j as f64 / (n - 0) as f64 * std::f64::consts::PI_2;
                let (cx, cy) = (x + w - radius, y + h - radius);
                Some([cx + angle.cos() * radius, cy + angle.sin() * radius])
            },
        }
    }, color, f);
}

/// Streams a polygon into tri list with color per vertex.
/// Uses buffers that fit inside L1 cache.
pub fn stream_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: || -> Option<[f64, ..2]>,
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let mut vertices: [f32, ..740] = [0.0, ..740];
    let mut colors: [f32, ..1480] = [0.0, ..1480];
    // Get the first point which will be used a lot.
    let fp = match polygon() { None => return, Some(val) => val };
    let (fx, fy) = (tx(m, fp[0], fp[1]), ty(m, fp[0], fp[1]));
    let gp = match polygon() { None => return, Some(val) => val };
    let (gx, gy) = (tx(m, gp[0], gp[1]), ty(m, gp[0], gp[1]));
    let mut gx = gx;
    let mut gy = gy;
    let mut i = 0;
    'read_vertices: loop {
        let ind_out = i * 2 * 3;
        vertices[ind_out + 0] = fx;
        vertices[ind_out + 1] = fy;
        let ind_out = i * 4 * 3;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];

        // Copy vertex.
        let ind_out = i * 2 * 3 + 2;
        let p =
            match polygon() {
                None => break 'read_vertices,
                Some(val) => val,
            };
        let x = tx(m, p[0], p[1]);
        let y = ty(m, p[0], p[1]);

        vertices[ind_out + 0] = gx;
        vertices[ind_out + 1] = gy;
        vertices[ind_out + 2] = x;
        vertices[ind_out + 3] = y;
        gx = x;
        gy = y;
        let ind_out = i * 4 * 3 + 4;
        colors[ind_out + 0] = color[0];
        colors[ind_out + 1] = color[1];
        colors[ind_out + 2] = color[2];
        colors[ind_out + 3] = color[3];
        colors[ind_out + 4] = color[0];
        colors[ind_out + 5] = color[1];
        colors[ind_out + 6] = color[2];
        colors[ind_out + 7] = color[3];

        i += 1;
        // Buffer is full.
        if i * 2 * 3 + 2 == vertices.len() {
            // Send chunk and start over.
            f(vertices.slice(0, i * 2 * 3),
                colors.slice(0, i * 4 * 3));
            i = 0;
        }
    }

    if i > 0 {
        f(vertices.slice(0, i * 2 * 3),
            colors.slice(0, i * 4 * 3));
    }
}

/// Splits polygon into convex segments with one color per vertex.
/// Create a buffer that fits into L1 cache with 1KB overhead.
pub fn with_polygon_tri_list_xy_f32_rgba_f32(
    m: &Matrix2d,
    polygon: &[f64],
    color: [f32, ..4],
    f: |vertices: &[f32], colors: &[f32]|) {

    let n = polygon.len();
    let mut i = 0;
    stream_polygon_tri_list_xy_f32_rgba_f32(
        m, || {
            if i >= n { return None; }

            let j = i;
            i += 2;
            Some([polygon[j], polygon[j+1]])
        }, color, f);
}

/// Creates triangle list vertices from rectangle.
pub fn rect_tri_list_xy_f32(m: &Matrix2d, rect: &Rectangle) -> [f32, ..12] {
    let (x, y, w, h) = (rect[0], rect[1], rect[2], rect[3]);
    let (x2, y2) = (x + w, y + h);
    [tx(m,x,y), ty(m,x,y), tx(m,x2,y), ty(m,x2,y), tx(m,x,y2), ty(m,x,y2),
     tx(m,x2,y), ty(m,x2,y), tx(m,x2,y2), ty(m,x2,y2), tx(m,x,y2), ty(m,x,y2)]
}

/// Creates triangle list colors from rectangle.
pub fn rect_tri_list_rgba_f32(color: [f32, ..4]) -> [f32, ..48] {
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    [r, g, b, a, // 0
     r, g, b, a, // 1
     r, g, b, a, // 2
     r, g, b, a, // 3
     r, g, b, a, // 4
     r, g, b, a, // 5
     r, g, b, a, // 6
     r, g, b, a, // 7
     r, g, b, a, // 8
     r, g, b, a, // 9
     r, g, b, a, // 10
     r, g, b, a]
}

/// Creates triangle list texture coords from image.
pub fn rect_tri_list_uv_f32(image: &Image) -> [f32, ..12] {
    let x1 = image.source_rect[0] as f32 / image.texture_width as f32;
    let y1 = image.source_rect[1] as f32 / image.texture_height as f32;
    let x2 = (image.source_rect[0] + image.source_rect[2]) as f32 / image.texture_width as f32;
    let y2 = (image.source_rect[1] + image.source_rect[3]) as f32 / image.texture_height as f32;
    [x1, y1, x2, y1, x1, y2,
     x2, y1, x2, y2, x1, y2]
}

<|endoftext|>


<commit_before>#![feature(std_misc)]

extern crate bootstrap_rs as bootstrap;
extern crate winapi;
extern crate kernel32;

use std::dynamic_lib::DynamicLibrary;
use std::path::Path;
use std::mem;
use std::thread;
use std::ops::DerefMut;
use std::fs;

use bootstrap::time::Timer;
use bootstrap::window::Window;

const TARGET_FRAME_TIME_MS: f32 = 1.0 / 60.0 * 1000.0;

type EngineInit = fn (Box<Window>) -> Box<()>;
type EngineUpdateAndRender = fn (&mut ());
type EngineReload = fn (Box<()>) -> Box<()>;
type EngineClose = fn (&()) -> bool;

const SRC_LIB: &'static str = "gunship-ed06d2369a03ebbb.dll";

fn update_dll(dest: &str) {
    // println!("remove file result: {:?}", fs::remove_file(LIB_PATH));
    println!("copy result: {:?}", fs::copy(SRC_LIB, dest));
}

/// # TODO
///
/// - Copy the complete game runtime into the new DLL's memory space when reloading, then have the old DLL clean
///   up the old data before releasing it.
/// - Keep track of the temp files made and then delete them when done running.
fn main() {
    let mut counter = 0..;

    // Statically create a window and load the renderer for the engine.
    let instance = bootstrap::init();
    let mut window = Window::new("Gunship Game", instance);
    let window_address = window.deref_mut() as *mut Window;

    // Open the game as a dynamic library.
    let (mut _lib, mut engine, mut engine_update_and_render, mut engine_close) = {
        let lib_path = format!("gunship_lib_{}.dll", counter.next().unwrap().to_string());
        update_dll(&lib_path);
        let lib = DynamicLibrary::open(Some(Path::new(&lib_path))).unwrap();

        let engine_init = unsafe {
            mem::transmute::<*mut EngineInit, EngineInit>(lib.symbol("engine_init").unwrap())
        };

        let engine_update_and_render = unsafe {
            mem::transmute::<*mut EngineUpdateAndRender, EngineUpdateAndRender>(lib.symbol("engine_update_and_render").unwrap())
        };

        let engine_close = unsafe {
            mem::transmute::<*mut EngineClose, EngineClose>(lib.symbol("engine_close").unwrap())
        };

        println!("calling engine_init()");
        let engine = engine_init(window);
        println!("done with engine_init()");

        (Some(lib), engine, engine_update_and_render, engine_close)
    };

    let timer = Timer::new();
    let mut reload_start = timer.now();
    loop {
        let start_time = timer.now();

        // Only reload every 5 seconds.
        if timer.elapsed(reload_start) > 5.0 {
            reload_start = timer.now();
            println!("time to reload library");

            let lib_path = format!("gunship_lib_{}.dll", counter.next().unwrap());
            update_dll(&lib_path);

            if let Ok(lib) = DynamicLibrary::open(Some(Path::new(&lib_path))) {
                println!("reloading library");

                let engine_reload = unsafe {
                    mem::transmute::<*mut EngineReload, EngineReload>(lib.symbol("engine_reload").unwrap())
                };

                engine_update_and_render = unsafe {
                    mem::transmute::<*mut EngineUpdateAndRender, EngineUpdateAndRender>(lib.symbol("engine_update_and_render").unwrap())
                };

                engine_close = unsafe {
                    mem::transmute::<*mut EngineClose, EngineClose>(lib.symbol("engine_close").unwrap())
                };

                println!("calling engine_reload()");
                engine = engine_reload(engine);
                println!("done with engine_reload()");

                // Drop the old dll and load the new one.
                _lib = Some(lib);
            }
        }

        unsafe {
            (&mut *window_address).handle_messages();
        }
        engine_update_and_render(&mut engine);
        if engine_close(&engine) {
            break;
        }

        // Wait for target frame time.
        let mut remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        while remaining_time_ms > 1.0 {
            thread::sleep_ms(remaining_time_ms as u32);
            remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        }

        while remaining_time_ms > 0.0 {
            remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        }
    }
}
<commit_msg>Only Reload DLL When Changed<commit_after>#![feature(std_misc, fs_time)]

extern crate bootstrap_rs as bootstrap;
extern crate winapi;
extern crate kernel32;

use std::dynamic_lib::DynamicLibrary;
use std::path::Path;
use std::mem;
use std::thread;
use std::ops::DerefMut;
use std::fs::{self, File};

use bootstrap::time::Timer;
use bootstrap::window::Window;

const TARGET_FRAME_TIME_MS: f32 = 1.0 / 60.0 * 1000.0;

type EngineInit = fn (Box<Window>) -> Box<()>;
type EngineUpdateAndRender = fn (&mut ());
type EngineReload = fn (Box<()>) -> Box<()>;
type EngineClose = fn (&()) -> bool;

const SRC_LIB: &'static str = "gunship-ed06d2369a03ebbb.dll";

fn update_dll(dest: &str, last_modified: &mut u64) -> bool {
    if let Ok(file) = File::open(SRC_LIB) {
        println!("Getting file metadata");
        let metadata = file.metadata().unwrap();
        let modified = metadata.modified();
        println!("last_modified: {}, modified: {}", last_modified, modified);

        if modified > *last_modified {
            println!("file has been updated");
            println!("copy result: {:?}", fs::copy(SRC_LIB, dest));
            *last_modified = modified;
            true
        } else {
            println!("file is the same");
            false
        }
    } else {
        println!("couldn't open file info");
        false
    }
}

/// # TODO
///
/// - Copy the complete game runtime into the new DLL's memory space when reloading, then have the old DLL clean
///   up the old data before releasing it.
/// - Keep track of the temp files made and then delete them when done running.
fn main() {
    let mut counter = 0..;

    // Statically create a window and load the renderer for the engine.
    let instance = bootstrap::init();
    let mut window = Window::new("Gunship Game", instance);
    let window_address = window.deref_mut() as *mut Window;

    // Open the game as a dynamic library.
    let mut last_modified = 0;
    let (mut _lib, mut engine, mut engine_update_and_render, mut engine_close) = {
        let lib_path = format!("gunship_lib_{}.dll", counter.next().unwrap().to_string());
        update_dll(&lib_path, &mut last_modified);
        let lib = DynamicLibrary::open(Some(Path::new(&lib_path))).unwrap();

        let engine_init = unsafe {
            mem::transmute::<*mut EngineInit, EngineInit>(lib.symbol("engine_init").unwrap())
        };

        let engine_update_and_render = unsafe {
            mem::transmute::<*mut EngineUpdateAndRender, EngineUpdateAndRender>(lib.symbol("engine_update_and_render").unwrap())
        };

        let engine_close = unsafe {
            mem::transmute::<*mut EngineClose, EngineClose>(lib.symbol("engine_close").unwrap())
        };

        println!("calling engine_init()");
        let engine = engine_init(window);
        println!("done with engine_init()");

        (Some(lib), engine, engine_update_and_render, engine_close)
    };

    let timer = Timer::new();
    loop {
        let start_time = timer.now();

        // Only reload if file has changed.
        let lib_path = format!("gunship_lib_{}.dll", counter.next().unwrap());
        if update_dll(&lib_path, &mut last_modified) {
            println!("reloading library");
            if let Ok(lib) = DynamicLibrary::open(Some(Path::new(&lib_path))) {
                println!("opened library");

                let engine_reload = unsafe {
                    mem::transmute::<*mut EngineReload, EngineReload>(lib.symbol("engine_reload").unwrap())
                };

                engine_update_and_render = unsafe {
                    mem::transmute::<*mut EngineUpdateAndRender, EngineUpdateAndRender>(lib.symbol("engine_update_and_render").unwrap())
                };

                engine_close = unsafe {
                    mem::transmute::<*mut EngineClose, EngineClose>(lib.symbol("engine_close").unwrap())
                };

                println!("calling engine_reload()");
                engine = engine_reload(engine);
                println!("done with engine_reload()");

                // Drop the old dll and load the new one.
                _lib = Some(lib);
            }
        }

        unsafe {
            (&mut *window_address).handle_messages();
        }
        engine_update_and_render(&mut engine);
        if engine_close(&engine) {
            break;
        }

        // Wait for target frame time.
        let mut remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        while remaining_time_ms > 1.0 {
            thread::sleep_ms(remaining_time_ms as u32);
            remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        }

        while remaining_time_ms > 0.0 {
            remaining_time_ms = TARGET_FRAME_TIME_MS - timer.elapsed_ms(start_time);
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vector
        impl<N> $name<$ty<N>> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Numeric
            , N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Numeric
            , N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Numeric
            , N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}
<commit_msg>[vector] Re-add impl_converts!<commit_after>macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_ops {
    ($ty: ident, $($sub: ident),+) => {
        impl_op! { Add for $ty, add, +, $($sub),+ }
        impl_op! { Sub for $ty, sub, -, $($sub),+ }
        impl_op! { Div for $ty, div, /, $($sub),+ }
        impl_op! { Rem for $ty, rem, %, $($sub),+ }
    }
}

macro_rules! impl_op {
    ($name: ident for $ty:ident, $fun: ident, $op:tt, $($sub: ident),+) => {
        // implement the operation for vector & vector
        impl<N> $name<$ty<N>> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs.$sub)),+ }
            }
        }

        // implement the operation for vector & scalar
        impl<N> $name<N> for $ty<N>
        where N: Numeric
            , N: $name<Output=N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Self::Output {
                $ty { $($sub: e!(self.$sub $op rhs)),+ }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy {

            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for $ty<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric
            , N: $name<Output = N> {

            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }

    }
}

macro_rules! impl_index {
    ($($v: ident),+) => { $(
        impl<N> ops::Index<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            type Output = N;
            #[inline] fn index(&self, i: usize) -> &N {
                &self.as_ref()[i]
            }
        }

        impl<N> ops::IndexMut<usize> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn index_mut(&mut self, i: usize) -> &mut N {
                &mut self.as_mut()[i]
            }
        }

        impl<N> Columnar for $v<N>
        where N: Numeric
            , N: Copy {

            type Column = $v<N>;
            #[inline] fn ncols(&self) -> usize { 1 }
            #[inline] fn column(&self, i: usize) -> Self::Column {
                if i == 0 { *self }
                else { panic!("Index out of bounds!") }
            }
            #[inline] fn column_mut(&mut self, i: usize) -> &mut Self::Column {
                if i == 0 { self }
                else { panic!("Index out of bounds!") }
            }

        }

        impl<N> Tabular for $v<N>
        where N: Numeric
            , N: Copy {

            type Row = N;
            #[inline] fn nrows(&self) -> usize { 3 }
            #[inline] fn row(&self, i: usize) -> Self::Row {
                self.as_ref()[i]
            }
            #[inline] fn row_mut(&mut self, i: usize) -> &mut Self::Row {
                &mut self.as_mut()[i]
            }

        }
    )+}
}

#[cfg(features = "rand")]
macro_rules! impl_rand {
    ($ty: ident, $($sub: ident),+) => {
        impl<N> Rand for $ty<N>
        where N: Numeric
            , N: Rand {

            fn rand<R: Rng>(rng: &mut R) -> Self {
                $ty { $($sub: N::rand(rng)),+ }
            }
        }
    }
}

macro_rules! impl_converts {
    ($($v: ident, $c: expr),+) => { $(
        impl<N> convert::AsRef<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_ref(&self) -> &[N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<N> convert::AsMut<[N; $c]> for $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn as_mut(&mut self) -> &mut [N; $c] {
                unsafe { transmute(self) }
            }
        }
        impl<'a, N> convert::From<&'a [N; $c]> for &'a $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a [N; $c]) -> &'a $v<N> {
                unsafe { transmute(a) }
            }
        }
        impl<'a, N> convert::From<&'a mut [N; $c]> for &'a mut $v<N>
        where N: Numeric
            , N: Copy {

            #[inline] fn from(a: &'a mut [N; $c]) -> &'a mut $v<N> {
                unsafe { transmute(a) }
            }
        }
        // impl<N: ?Sized> From<[N; $c]> for $v<N>
        // where N: Numeric
        //     , N: Copy {
        //     #[inline]
        //     fn from(a: [N; $c]) -> $v<N> {
        //         unsafe { transmute(a) }
        //     }
        // }
    )+}
}
<|endoftext|>