<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Foo<T: ?Sized> {
    a: u16,
    b: T
}

trait Bar {
    fn get(&self) -> usize;
}

impl Bar for usize {
    fn get(&self) -> usize { *self }
}

struct Baz<T: ?Sized> {
    a: T
}

#[repr(packed)]
struct Packed<T: ?Sized> {
    a: u8,
    b: T
}

struct HasDrop<T: ?Sized> {
    ptr: Box<usize>,
    data: T
}

fn main() {
    // Test that zero-offset works properly
    let b : Baz<usize> = Baz { a: 7 };
    assert_eq!(b.a.get(), 7);
    let b : &Baz<Bar> = &b;
    assert_eq!(b.a.get(), 7);

    // Test that the field is aligned properly
    let f : Foo<usize> = Foo { a: 0, b: 11 };
    assert_eq!(f.b.get(), 11);
    let ptr1 : *const u8 = &f.b as *const _ as *const u8;

    let f : &Foo<Bar> = &f;
    let ptr2 : *const u8 = &f.b as *const _ as *const u8;
    assert_eq!(f.b.get(), 11);

    // The pointers should be the same
    assert_eq!(ptr1, ptr2);

    // Test that packed structs are handled correctly
    let p : Packed<usize> = Packed { a: 0, b: 13 };
    assert_eq!(p.b.get(), 13);
    let p : &Packed<Bar> = &p;
    assert_eq!(p.b.get(), 13);

    // Test that nested DSTs work properly
    let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
    assert_eq!(f.b.b.get(), 17);
    let f : &Foo<Foo<Bar>> = &f;
    assert_eq!(f.b.b.get(), 17);

    // Test that get the pointer via destructuring works

    let f : Foo<usize> = Foo { a: 0, b: 11 };
    let f : &Foo<Bar> = &f;
    let &Foo { a: _, b: ref bar } = f;
    assert_eq!(bar.get(), 11);

    // Make sure that drop flags don't screw things up

    let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
        ptr: Box::new(0),
        data: Baz { a: [1,2,3,4] }
    };
    assert_eq!([1,2,3,4], d.data.a);

    let d : &HasDrop<Baz<[i32]>> = &d;
    assert_eq!(&[1,2,3,4], &d.data.a);
}
<commit_msg>Rollup merge of #39692 - oli-obk:patch-2, r=aturon<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

struct Foo<T: ?Sized> {
    a: u16,
    b: T
}

trait Bar {
    fn get(&self) -> usize;
}

impl Bar for usize {
    fn get(&self) -> usize { *self }
}

struct Baz<T: ?Sized> {
    a: T
}

struct HasDrop<T: ?Sized> {
    ptr: Box<usize>,
    data: T
}

fn main() {
    // Test that zero-offset works properly
    let b : Baz<usize> = Baz { a: 7 };
    assert_eq!(b.a.get(), 7);
    let b : &Baz<Bar> = &b;
    assert_eq!(b.a.get(), 7);

    // Test that the field is aligned properly
    let f : Foo<usize> = Foo { a: 0, b: 11 };
    assert_eq!(f.b.get(), 11);
    let ptr1 : *const u8 = &f.b as *const _ as *const u8;

    let f : &Foo<Bar> = &f;
    let ptr2 : *const u8 = &f.b as *const _ as *const u8;
    assert_eq!(f.b.get(), 11);

    // The pointers should be the same
    assert_eq!(ptr1, ptr2);

    // Test that nested DSTs work properly
    let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
    assert_eq!(f.b.b.get(), 17);
    let f : &Foo<Foo<Bar>> = &f;
    assert_eq!(f.b.b.get(), 17);

    // Test that get the pointer via destructuring works

    let f : Foo<usize> = Foo { a: 0, b: 11 };
    let f : &Foo<Bar> = &f;
    let &Foo { a: _, b: ref bar } = f;
    assert_eq!(bar.get(), 11);

    // Make sure that drop flags don't screw things up

    let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
        ptr: Box::new(0),
        data: Baz { a: [1,2,3,4] }
    };
    assert_eq!([1,2,3,4], d.data.a);

    let d : &HasDrop<Baz<[i32]>> = &d;
    assert_eq!(&[1,2,3,4], &d.data.a);
}
<|endoftext|>


<commit_before>//! Emulation of a subset of the cpuid x86 instruction.

use crate::prelude::*;

/// Emulates a subset of the cpuid x86 instruction.
///
/// This emulates an intel cpu with sse and sse2 support, but which doesn't support anything else.
pub(crate) fn codegen_cpuid_call<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    leaf: Value,
    _sub_leaf: Value,
) -> (Value, Value, Value, Value) {
    let leaf_0 = fx.bcx.create_block();
    let leaf_1 = fx.bcx.create_block();
    let leaf_8000_0000 = fx.bcx.create_block();
    let leaf_8000_0001 = fx.bcx.create_block();
    let unsupported_leaf = fx.bcx.create_block();

    let dest = fx.bcx.create_block();
    let eax = fx.bcx.append_block_param(dest, types::I32);
    let ebx = fx.bcx.append_block_param(dest, types::I32);
    let ecx = fx.bcx.append_block_param(dest, types::I32);
    let edx = fx.bcx.append_block_param(dest, types::I32);

    let mut switch = cranelift_frontend::Switch::new();
    switch.set_entry(0, leaf_0);
    switch.set_entry(1, leaf_1);
    switch.set_entry(0x8000_0000, leaf_8000_0000);
    switch.set_entry(0x8000_0001, leaf_8000_0001);
    switch.emit(&mut fx.bcx, leaf, unsupported_leaf);

    fx.bcx.switch_to_block(leaf_0);
    let max_basic_leaf = fx.bcx.ins().iconst(types::I32, 1);
    let vend0 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"Genu")));
    let vend2 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ineI")));
    let vend1 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ntel")));
    fx.bcx.ins().jump(dest, &[max_basic_leaf, vend0, vend1, vend2]);

    fx.bcx.switch_to_block(leaf_1);
    let cpu_signature = fx.bcx.ins().iconst(types::I32, 0);
    let additional_information = fx.bcx.ins().iconst(types::I32, 0);
    let ecx_features = fx.bcx.ins().iconst(types::I32, 0);
    let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
    fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);

    fx.bcx.switch_to_block(leaf_8000_0000);
    let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
    let zero = fx.bcx.ins().iconst(types::I32, 0);
    fx.bcx.ins().jump(dest, &[extended_max_basic_leaf, zero, zero, zero]);

    fx.bcx.switch_to_block(leaf_8000_0001);
    let zero = fx.bcx.ins().iconst(types::I32, 0);
    let proc_info_ecx = fx.bcx.ins().iconst(types::I32, 0);
    let proc_info_edx = fx.bcx.ins().iconst(types::I32, 0);
    fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);

    fx.bcx.switch_to_block(unsupported_leaf);
    crate::trap::trap_unreachable(
        fx,
        "__cpuid_count arch intrinsic doesn't yet support specified leaf",
    );

    fx.bcx.switch_to_block(dest);
    fx.bcx.ins().nop();

    (eax, ebx, ecx, edx)
}
<commit_msg>Return 0 from cpuid for all subleaves of leaf 7<commit_after>//! Emulation of a subset of the cpuid x86 instruction.

use crate::prelude::*;

/// Emulates a subset of the cpuid x86 instruction.
///
/// This emulates an intel cpu with sse and sse2 support, but which doesn't support anything else.
pub(crate) fn codegen_cpuid_call<'tcx>(
    fx: &mut FunctionCx<'_, '_, 'tcx>,
    leaf: Value,
    _sub_leaf: Value,
) -> (Value, Value, Value, Value) {
    let leaf_0 = fx.bcx.create_block();
    let leaf_1 = fx.bcx.create_block();
    let leaf_7 = fx.bcx.create_block();
    let leaf_8000_0000 = fx.bcx.create_block();
    let leaf_8000_0001 = fx.bcx.create_block();
    let unsupported_leaf = fx.bcx.create_block();

    let dest = fx.bcx.create_block();
    let eax = fx.bcx.append_block_param(dest, types::I32);
    let ebx = fx.bcx.append_block_param(dest, types::I32);
    let ecx = fx.bcx.append_block_param(dest, types::I32);
    let edx = fx.bcx.append_block_param(dest, types::I32);

    let mut switch = cranelift_frontend::Switch::new();
    switch.set_entry(0, leaf_0);
    switch.set_entry(1, leaf_1);
    switch.set_entry(7, leaf_7);
    switch.set_entry(0x8000_0000, leaf_8000_0000);
    switch.set_entry(0x8000_0001, leaf_8000_0001);
    switch.emit(&mut fx.bcx, leaf, unsupported_leaf);

    fx.bcx.switch_to_block(leaf_0);
    let max_basic_leaf = fx.bcx.ins().iconst(types::I32, 1);
    let vend0 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"Genu")));
    let vend2 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ineI")));
    let vend1 = fx.bcx.ins().iconst(types::I32, i64::from(u32::from_le_bytes(*b"ntel")));
    fx.bcx.ins().jump(dest, &[max_basic_leaf, vend0, vend1, vend2]);

    fx.bcx.switch_to_block(leaf_1);
    let cpu_signature = fx.bcx.ins().iconst(types::I32, 0);
    let additional_information = fx.bcx.ins().iconst(types::I32, 0);
    let ecx_features = fx.bcx.ins().iconst(types::I32, 0);
    let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
    fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);

    fx.bcx.switch_to_block(leaf_7);
    // This leaf technically has subleaves, but we just return zero for all subleaves.
    let zero = fx.bcx.ins().iconst(types::I32, 0);
    fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);

    fx.bcx.switch_to_block(leaf_8000_0000);
    let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
    let zero = fx.bcx.ins().iconst(types::I32, 0);
    fx.bcx.ins().jump(dest, &[extended_max_basic_leaf, zero, zero, zero]);

    fx.bcx.switch_to_block(leaf_8000_0001);
    let zero = fx.bcx.ins().iconst(types::I32, 0);
    let proc_info_ecx = fx.bcx.ins().iconst(types::I32, 0);
    let proc_info_edx = fx.bcx.ins().iconst(types::I32, 0);
    fx.bcx.ins().jump(dest, &[zero, zero, proc_info_ecx, proc_info_edx]);

    fx.bcx.switch_to_block(unsupported_leaf);
    crate::trap::trap_unreachable(
        fx,
        "__cpuid_count arch intrinsic doesn't yet support specified leaf",
    );

    fx.bcx.switch_to_block(dest);
    fx.bcx.ins().nop();

    (eax, ebx, ecx, edx)
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Base64 binary-to-text encoding

use std::vec;

/// A trait for converting a value to base64 encoding.
pub trait ToBase64 {
    /// Converts the value of `self` to a base64 value, returning the owned
    /// string
    fn to_base64(&self) -> ~str;
}

static CHARS: [char, ..64] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
];

impl<'self> ToBase64 for &'self [u8] {
    /**
     * Turn a vector of `u8` bytes into a base64 string.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::ToBase64;
     *
     * fn main () {
     *     let str = [52,32].to_base64();
     *     println(fmt!("%s", str));
     * }
     * ~~~
     */
    fn to_base64(&self) -> ~str {
        let mut s = ~"";
        let len = self.len();
        s.reserve(((len + 3u) / 4u) * 3u);

        let mut i = 0u;

        while i < len - (len % 3u) {
            let n = (self[i] as uint) << 16u |
                    (self[i + 1u] as uint) << 8u |
                    (self[i + 2u] as uint);

            // This 24-bit number gets separated into four 6-bit numbers.
            s.push_char(CHARS[(n >> 18u) & 63u]);
            s.push_char(CHARS[(n >> 12u) & 63u]);
            s.push_char(CHARS[(n >> 6u) & 63u]);
            s.push_char(CHARS[n & 63u]);

            i += 3u;
        }

        // Heh, would be cool if we knew this was exhaustive
        // (the dream of bounded integer types)
        match len % 3 {
          0 => (),
          1 => {
            let n = (self[i] as uint) << 16u;
            s.push_char(CHARS[(n >> 18u) & 63u]);
            s.push_char(CHARS[(n >> 12u) & 63u]);
            s.push_char('=');
            s.push_char('=');
          }
          2 => {
            let n = (self[i] as uint) << 16u |
                (self[i + 1u] as uint) << 8u;
            s.push_char(CHARS[(n >> 18u) & 63u]);
            s.push_char(CHARS[(n >> 12u) & 63u]);
            s.push_char(CHARS[(n >> 6u) & 63u]);
            s.push_char('=');
          }
          _ => fail!("Algebra is broken, please alert the math police")
        }
        s
    }
}

impl<'self> ToBase64 for &'self str {
    /**
     * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
     *
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::ToBase64;
     *
     * fn main () {
     *     let str = "Hello, World".to_base64();
     *     println(fmt!("%s",str));
     * }
     * ~~~
     *
     */
    fn to_base64(&self) -> ~str {
        self.as_bytes().to_base64()
    }
}

#[allow(missing_doc)]
pub trait FromBase64 {
    fn from_base64(&self) -> ~[u8];
}

impl<'self> FromBase64 for &'self [u8] {
    /**
     * Convert base64 `u8` vector into u8 byte values.
     * Every 4 encoded characters is converted into 3 octets, modulo padding.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::ToBase64;
     * use extra::base64::FromBase64;
     *
     * fn main () {
     *     let str = [52,32].to_base64();
     *     println(fmt!("%s", str));
     *     let bytes = str.from_base64();
     *     println(fmt!("%?",bytes));
     * }
     * ~~~
     */
    fn from_base64(&self) -> ~[u8] {
        if self.len() % 4u != 0u { fail!("invalid base64 length"); }

        let len = self.len();
        let mut padding = 0u;

        if len != 0u {
            if self[len - 1u] == '=' as u8 { padding += 1u; }
            if self[len - 2u] == '=' as u8 { padding += 1u; }
        }

        let mut r = vec::with_capacity((len / 4u) * 3u - padding);

        let mut i = 0u;
        while i < len {
            let mut n = 0u;

            for 4u.times {
                let ch = self[i] as char;
                n <<= 6u;

                match ch {
                    'A'..'Z' => n |= (ch as uint) - 0x41,
                    'a'..'z' => n |= (ch as uint) - 0x47,
                    '0'..'9' => n |= (ch as uint) + 0x04,
                    '+'      => n |= 0x3E,
                    '/'      => n |= 0x3F,
                    '='      => {
                        match len - i {
                            1u => {
                                r.push(((n >> 16u) & 0xFFu) as u8);
                                r.push(((n >> 8u ) & 0xFFu) as u8);
                                return copy r;
                            }
                            2u => {
                                r.push(((n >> 10u) & 0xFFu) as u8);
                                return copy r;
                            }
                            _ => fail!("invalid base64 padding")
                        }
                    }
                    _ => fail!("invalid base64 character")
                }

                i += 1u;
            };

            r.push(((n >> 16u) & 0xFFu) as u8);
            r.push(((n >> 8u ) & 0xFFu) as u8);
            r.push(((n       ) & 0xFFu) as u8);
        }
        r
    }
}

impl<'self> FromBase64 for &'self str {
    /**
     * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
     * to the byte values it encodes.
     *
     * You can use the `from_bytes` function in `std::str`
     * to turn a `[u8]` into a string with characters corresponding to those values.
     *
     * # Example
     *
     * This converts a string literal to base64 and back.
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::ToBase64;
     * use extra::base64::FromBase64;
     * use std::str;
     *
     * fn main () {
     *     let hello_str = "Hello, World".to_base64();
     *     println(fmt!("%s",hello_str));
     *     let bytes = hello_str.from_base64();
     *     println(fmt!("%?",bytes));
     *     let result_str = str::from_bytes(bytes);
     *     println(fmt!("%s",result_str));
     * }
     * ~~~
     */
    fn from_base64(&self) -> ~[u8] {
        self.as_bytes().from_base64()
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_to_base64() {
        assert_eq!("".to_base64(), ~"");
        assert_eq!("f".to_base64(), ~"Zg==");
        assert_eq!("fo".to_base64(), ~"Zm8=");
        assert_eq!("foo".to_base64(), ~"Zm9v");
        assert_eq!("foob".to_base64(), ~"Zm9vYg==");
        assert_eq!("fooba".to_base64(), ~"Zm9vYmE=");
        assert_eq!("foobar".to_base64(), ~"Zm9vYmFy");
    }

    #[test]
    fn test_from_base64() {
        assert_eq!("".from_base64(), "".as_bytes().to_owned());
        assert_eq!("Zg==".from_base64(), "f".as_bytes().to_owned());
        assert_eq!("Zm8=".from_base64(), "fo".as_bytes().to_owned());
        assert_eq!("Zm9v".from_base64(), "foo".as_bytes().to_owned());
        assert_eq!("Zm9vYg==".from_base64(), "foob".as_bytes().to_owned());
        assert_eq!("Zm9vYmE=".from_base64(), "fooba".as_bytes().to_owned());
        assert_eq!("Zm9vYmFy".from_base64(), "foobar".as_bytes().to_owned());
    }
}
<commit_msg>auto merge of #7513 : sfackler/rust/master, r=msullivan<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Base64 binary-to-text encoding

/// Available encoding character sets
pub enum CharacterSet {
    /// The standard character set (uses '+' and '/')
    Standard,
    /// The URL safe character set (uses '-' and '_')
    UrlSafe
}

/// Contains configuration parameters for to_base64
pub struct Config {
    /// Character set to use
    char_set: CharacterSet,
    /// True to pad output with '=' characters
    pad: bool,
    /// Some(len) to wrap lines at len, None to disable line wrapping
    line_length: Option<uint>
}

/// Configuration for RFC 4648 standard base64 encoding
pub static STANDARD: Config =
    Config {char_set: Standard, pad: true, line_length: None};

/// Configuration for RFC 4648 base64url encoding
pub static URL_SAFE: Config =
    Config {char_set: UrlSafe, pad: false, line_length: None};

/// Configuration for RFC 2045 MIME base64 encoding
pub static MIME: Config =
    Config {char_set: Standard, pad: true, line_length: Some(76)};

static STANDARD_CHARS: [char, ..64] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
];

static URLSAFE_CHARS: [char, ..64] = [
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
];

/// A trait for converting a value to base64 encoding.
pub trait ToBase64 {
    /// Converts the value of `self` to a base64 value following the specified
    /// format configuration, returning the owned string.
    fn to_base64(&self, config: Config) -> ~str;
}

impl<'self> ToBase64 for &'self [u8] {
    /**
     * Turn a vector of `u8` bytes into a base64 string.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::{ToBase64, standard};
     *
     * fn main () {
     *     let str = [52,32].to_base64(standard);
     *     println(fmt!("%s", str));
     * }
     * ~~~
     */
    fn to_base64(&self, config: Config) -> ~str {
        let chars = match config.char_set {
            Standard => STANDARD_CHARS,
            UrlSafe => URLSAFE_CHARS
        };

        let mut s = ~"";
        let mut i = 0;
        let mut cur_length = 0;
        let len = self.len();
        while i < len - (len % 3) {
            match config.line_length {
                Some(line_length) =>
                    if cur_length >= line_length {
                        s.push_str("\r\n");
                        cur_length = 0;
                    },
                None => ()
            }

            let n = (self[i] as u32) << 16 |
                    (self[i + 1] as u32) << 8 |
                    (self[i + 2] as u32);

            // This 24-bit number gets separated into four 6-bit numbers.
            s.push_char(chars[(n >> 18) & 63]);
            s.push_char(chars[(n >> 12) & 63]);
            s.push_char(chars[(n >> 6 ) & 63]);
            s.push_char(chars[n & 63]);

            cur_length += 4;
            i += 3;
        }

        if len % 3 != 0 {
            match config.line_length {
                Some(line_length) =>
                    if cur_length >= line_length {
                        s.push_str("\r\n");
                    },
                None => ()
            }
        }

        // Heh, would be cool if we knew this was exhaustive
        // (the dream of bounded integer types)
        match len % 3 {
            0 => (),
            1 => {
                let n = (self[i] as u32) << 16;
                s.push_char(chars[(n >> 18) & 63]);
                s.push_char(chars[(n >> 12) & 63]);
                if config.pad {
                    s.push_str("==");
                }
            }
            2 => {
                let n = (self[i] as u32) << 16 |
                    (self[i + 1u] as u32) << 8;
                s.push_char(chars[(n >> 18) & 63]);
                s.push_char(chars[(n >> 12) & 63]);
                s.push_char(chars[(n >> 6 ) & 63]);
                if config.pad {
                    s.push_char('=');
                }
            }
            _ => fail!("Algebra is broken, please alert the math police")
        }
        s
    }
}

impl<'self> ToBase64 for &'self str {
    /**
     * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding.
     *
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::{ToBase64, standard};
     *
     * fn main () {
     *     let str = "Hello, World".to_base64(standard);
     *     println(fmt!("%s",str));
     * }
     * ~~~
     *
     */
    fn to_base64(&self, config: Config) -> ~str {
        self.as_bytes().to_base64(config)
    }
}

/// A trait for converting from base64 encoded values.
pub trait FromBase64 {
    /// Converts the value of `self`, interpreted as base64 encoded data, into
    /// an owned vector of bytes, returning the vector.
    fn from_base64(&self) -> Result<~[u8], ~str>;
}

impl<'self> FromBase64 for &'self [u8] {
    /**
     * Convert base64 `u8` vector into u8 byte values.
     * Every 4 encoded characters is converted into 3 octets, modulo padding.
     *
     * # Example
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::{ToBase64, FromBase64, standard};
     *
     * fn main () {
     *     let str = [52,32].to_base64(standard);
     *     println(fmt!("%s", str));
     *     let bytes = str.from_base64();
     *     println(fmt!("%?",bytes));
     * }
     * ~~~
     */
    fn from_base64(&self) -> Result<~[u8], ~str> {
        let mut r = ~[];
        let mut buf: u32 = 0;
        let mut modulus = 0;

        let mut it = self.iter();
        for it.advance |&byte| {
            let ch = byte as char;
            let val = byte as u32;

            match ch {
                'A'..'Z'  => buf |= val - 0x41,
                'a'..'z'  => buf |= val - 0x47,
                '0'..'9'  => buf |= val + 0x04,
                '+'|'-'   => buf |= 0x3E,
                '/'|'_'   => buf |= 0x3F,
                '\r'|'\n' => loop,
                '='       => break,
                _         => return Err(~"Invalid Base64 character")
            }

            buf <<= 6;
            modulus += 1;
            if modulus == 4 {
                modulus = 0;
                r.push((buf >> 22) as u8);
                r.push((buf >> 14) as u8);
                r.push((buf >> 6 ) as u8);
            }
        }

        if !it.all(|&byte| {byte as char == '='}) {
            return Err(~"Invalid Base64 character");
        }

        match modulus {
            2 => {
                r.push((buf >> 10) as u8);
            }
            3 => {
                r.push((buf >> 16) as u8);
                r.push((buf >> 8 ) as u8);
            }
            0 => (),
            _ => return Err(~"Invalid Base64 length")
        }

        Ok(r)
    }
}

impl<'self> FromBase64 for &'self str {
    /**
     * Convert any base64 encoded string (literal, `@`, `&`, or `~`)
     * to the byte values it encodes.
     *
     * You can use the `from_bytes` function in `std::str`
     * to turn a `[u8]` into a string with characters corresponding to those
     * values.
     *
     * # Example
     *
     * This converts a string literal to base64 and back.
     *
     * ~~~ {.rust}
     * extern mod extra;
     * use extra::base64::{ToBase64, FromBase64, standard};
     * use std::str;
     *
     * fn main () {
     *     let hello_str = "Hello, World".to_base64(standard);
     *     println(fmt!("%s",hello_str));
     *     let bytes = hello_str.from_base64();
     *     println(fmt!("%?",bytes));
     *     let result_str = str::from_bytes(bytes);
     *     println(fmt!("%s",result_str));
     * }
     * ~~~
     */
    fn from_base64(&self) -> Result<~[u8], ~str> {
        self.as_bytes().from_base64()
    }
}

#[test]
fn test_to_base64_basic() {
    assert_eq!("".to_base64(STANDARD), ~"");
    assert_eq!("f".to_base64(STANDARD), ~"Zg==");
    assert_eq!("fo".to_base64(STANDARD), ~"Zm8=");
    assert_eq!("foo".to_base64(STANDARD), ~"Zm9v");
    assert_eq!("foob".to_base64(STANDARD), ~"Zm9vYg==");
    assert_eq!("fooba".to_base64(STANDARD), ~"Zm9vYmE=");
    assert_eq!("foobar".to_base64(STANDARD), ~"Zm9vYmFy");
}

#[test]
fn test_to_base64_line_break() {
    assert!(![0u8, 1000].to_base64(Config {line_length: None, ..STANDARD})
        .contains("\r\n"));
    assert_eq!("foobar".to_base64(Config {line_length: Some(4), ..STANDARD}),
        ~"Zm9v\r\nYmFy");
}

#[test]
fn test_to_base64_padding() {
    assert_eq!("f".to_base64(Config {pad: false, ..STANDARD}), ~"Zg");
    assert_eq!("fo".to_base64(Config {pad: false, ..STANDARD}), ~"Zm8");
}

#[test]
fn test_to_base64_url_safe() {
    assert_eq!([251, 255].to_base64(URL_SAFE), ~"-_8");
    assert_eq!([251, 255].to_base64(STANDARD), ~"+/8=");
}

#[test]
fn test_from_base64_basic() {
    assert_eq!("".from_base64().get(), "".as_bytes().to_owned());
    assert_eq!("Zg==".from_base64().get(), "f".as_bytes().to_owned());
    assert_eq!("Zm8=".from_base64().get(), "fo".as_bytes().to_owned());
    assert_eq!("Zm9v".from_base64().get(), "foo".as_bytes().to_owned());
    assert_eq!("Zm9vYg==".from_base64().get(), "foob".as_bytes().to_owned());
    assert_eq!("Zm9vYmE=".from_base64().get(), "fooba".as_bytes().to_owned());
    assert_eq!("Zm9vYmFy".from_base64().get(), "foobar".as_bytes().to_owned());
}

#[test]
fn test_from_base64_newlines() {
    assert_eq!("Zm9v\r\nYmFy".from_base64().get(),
        "foobar".as_bytes().to_owned());
}

#[test]
fn test_from_base64_urlsafe() {
    assert_eq!("-_8".from_base64().get(), "+/8=".from_base64().get());
}

#[test]
fn test_from_base64_invalid_char() {
    assert!("Zm$=".from_base64().is_err())
    assert!("Zg==$".from_base64().is_err());
}

#[test]
fn test_from_base64_invalid_padding() {
    assert!("Z===".from_base64().is_err());
}

#[test]
fn test_base64_random() {
    use std::rand::{task_rng, random, RngUtil};
    use std::vec;

    for 1000.times {
        let v: ~[u8] = do vec::build |push| {
            for task_rng().gen_uint_range(1, 100).times {
                push(random());
            }
        };
        assert_eq!(v.to_base64(STANDARD).from_base64().get(), v);
    }
}
<|endoftext|>


<commit_before>//! Implementation of configuration for various sources
//!
//! This module will parse the various `source.*` TOML configuration keys into a
//! structure usable by Cargo itself. Currently this is primarily used to map
//! sources to one another via the `replace-with` key in `.cargo/config`.

use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;

use core::{Source, SourceId};
use sources::ReplacedSource;
use util::{Config, ToUrl};
use util::config::ConfigValue;
use util::errors::{CargoError, CargoResult, CargoResultExt};

pub struct SourceConfigMap<'cfg> {
    cfgs: HashMap<String, SourceConfig>,
    id2name: HashMap<SourceId, String>,
    config: &'cfg Config,
}

/// Configuration for a particular source, found in TOML looking like:
///
/// ```toml
/// [source.crates-io]
/// registry = 'https://github.com/rust-lang/crates.io-index'
/// replace-with = 'foo'    # optional
/// ```
struct SourceConfig {
    // id this source corresponds to, inferred from the various defined keys in
    // the configuration
    id: SourceId,

    // Name of the source that this source should be replaced with. This field
    // is a tuple of (name, path) where path is where this configuration key was
    // defined (the literal `.cargo/config` file).
    replace_with: Option<(String, PathBuf)>,
}

impl<'cfg> SourceConfigMap<'cfg> {
    pub fn new(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> {
        let mut base = SourceConfigMap::empty(config)?;
        if let Some(table) = config.get_table("source")? {
            for (key, value) in table.val.iter() {
                base.add_config(key, value)?;
            }
        }
        Ok(base)
    }

    pub fn empty(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> {
        let mut base = SourceConfigMap {
            cfgs: HashMap::new(),
            id2name: HashMap::new(),
            config: config,
        };
        base.add("crates-io", SourceConfig {
            id: SourceId::crates_io(config)?,
            replace_with: None,
        });
        Ok(base)
    }

    pub fn config(&self) -> &'cfg Config {
        self.config
    }

    pub fn load(&self, id: &SourceId) -> CargoResult<Box<Source + 'cfg>> {
        debug!("loading: {}", id);
        let mut name = match self.id2name.get(id) {
            Some(name) => name,
            None => return Ok(id.load(self.config)),
        };
        let mut path = Path::new("/");
        let orig_name = name;
        let new_id;
        loop {
            let cfg = match self.cfgs.get(name) {
                Some(cfg) => cfg,
                None => bail!("could not find a configured source with the \
                               name `{}` when attempting to lookup `{}` \
                               (configuration in `{}`)",
                              name, orig_name, path.display()),
            };
            match cfg.replace_with {
                Some((ref s, ref p)) => {
                    name = s;
                    path = p;
                }
                None if *id == cfg.id => return Ok(id.load(self.config)),
                None => {
                    new_id = cfg.id.with_precise(id.precise()
                                                 .map(|s| s.to_string()));
                    break
                }
            }
            debug!("following pointer to {}", name);
            if name == orig_name {
                bail!("detected a cycle of `replace-with` sources, the source \
                       `{}` is eventually replaced with itself \
                       (configuration in `{}`)", name, path.display())
            }
        }
        let new_src = new_id.load(self.config);
        let old_src = id.load(self.config);
        if new_src.supports_checksums() != old_src.supports_checksums() {
            let (supports, no_support) = if new_src.supports_checksums() {
                (name, orig_name)
            } else {
                (orig_name, name)
            };
            bail!("\
cannot replace `{orig}` with `{name}`, the source `{supports}` supports \
checksums, but `{no_support}` does not

a lock file compatible with `{orig}` cannot be generated in this situation
", orig = orig_name, name = name, supports = supports, no_support = no_support);
        }
        Ok(Box::new(ReplacedSource::new(id, &new_id, new_src)))
    }

    fn add(&mut self, name: &str, cfg: SourceConfig) {
        self.id2name.insert(cfg.id.clone(), name.to_string());
        self.cfgs.insert(name.to_string(), cfg);
    }

    fn add_config(&mut self, name: &str, cfg: &ConfigValue) -> CargoResult<()> {
        let (table, _path) = cfg.table(&format!("source.{}", name))?;
        let mut srcs = Vec::new();
        if let Some(val) = table.get("registry") {
            let url = url(val, &format!("source.{}.registry", name))?;
            srcs.push(SourceId::for_registry(&url));
        }
        if let Some(val) = table.get("local-registry") {
            let (s, path) = val.string(&format!("source.{}.local-registry",
                                                     name))?;
            let mut path = path.to_path_buf();
            path.pop();
            path.pop();
            path.push(s);
            srcs.push(SourceId::for_local_registry(&path)?);
        }
        if let Some(val) = table.get("directory") {
            let (s, path) = val.string(&format!("source.{}.directory",
                                                     name))?;
            let mut path = path.to_path_buf();
            path.pop();
            path.pop();
            path.push(s);
            srcs.push(SourceId::for_directory(&path)?);
        }
        if name == "crates-io" && srcs.is_empty() {
            srcs.push(SourceId::crates_io(self.config)?);
        }

        let mut srcs = srcs.into_iter();
        let src = srcs.next().ok_or_else(|| {
            CargoError::from(format!("no source URL specified for `source.{}`, need \
                                      either `registry` or `local-registry` defined",
                                     name))
        })?;
        if srcs.next().is_some() {
            return Err(format!("more than one source URL specified for \
                                `source.{}`", name).into())
        }

        let mut replace_with = None;
        if let Some(val) = table.get("replace-with") {
            let (s, path) = val.string(&format!("source.{}.replace-with",
                                                     name))?;
            replace_with = Some((s.to_string(), path.to_path_buf()));
        }

        self.add(name, SourceConfig {
            id: src,
            replace_with: replace_with,
        });

        return Ok(());

        fn url(cfg: &ConfigValue, key: &str) -> CargoResult<Url> {
            let (url, path) = cfg.string(key)?;
            url.to_url().chain_err(|| {
                format!("configuration key `{}` specified an invalid \
                         URL (in {})", key, path.display())

            })
        }
    }
}
<commit_msg>make SourceConfigMap cloneable<commit_after>//! Implementation of configuration for various sources
//!
//! This module will parse the various `source.*` TOML configuration keys into a
//! structure usable by Cargo itself. Currently this is primarily used to map
//! sources to one another via the `replace-with` key in `.cargo/config`.

use std::collections::HashMap;
use std::path::{Path, PathBuf};

use url::Url;

use core::{Source, SourceId};
use sources::ReplacedSource;
use util::{Config, ToUrl};
use util::config::ConfigValue;
use util::errors::{CargoError, CargoResult, CargoResultExt};

#[derive(Clone)]
pub struct SourceConfigMap<'cfg> {
    cfgs: HashMap<String, SourceConfig>,
    id2name: HashMap<SourceId, String>,
    config: &'cfg Config,
}

/// Configuration for a particular source, found in TOML looking like:
///
/// ```toml
/// [source.crates-io]
/// registry = 'https://github.com/rust-lang/crates.io-index'
/// replace-with = 'foo'    # optional
/// ```
#[derive(Clone)]
struct SourceConfig {
    // id this source corresponds to, inferred from the various defined keys in
    // the configuration
    id: SourceId,

    // Name of the source that this source should be replaced with. This field
    // is a tuple of (name, path) where path is where this configuration key was
    // defined (the literal `.cargo/config` file).
    replace_with: Option<(String, PathBuf)>,
}

impl<'cfg> SourceConfigMap<'cfg> {
    pub fn new(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> {
        let mut base = SourceConfigMap::empty(config)?;
        if let Some(table) = config.get_table("source")? {
            for (key, value) in table.val.iter() {
                base.add_config(key, value)?;
            }
        }
        Ok(base)
    }

    pub fn empty(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> {
        let mut base = SourceConfigMap {
            cfgs: HashMap::new(),
            id2name: HashMap::new(),
            config: config,
        };
        base.add("crates-io", SourceConfig {
            id: SourceId::crates_io(config)?,
            replace_with: None,
        });
        Ok(base)
    }

    pub fn config(&self) -> &'cfg Config {
        self.config
    }

    pub fn load(&self, id: &SourceId) -> CargoResult<Box<Source + 'cfg>> {
        debug!("loading: {}", id);
        let mut name = match self.id2name.get(id) {
            Some(name) => name,
            None => return Ok(id.load(self.config)),
        };
        let mut path = Path::new("/");
        let orig_name = name;
        let new_id;
        loop {
            let cfg = match self.cfgs.get(name) {
                Some(cfg) => cfg,
                None => bail!("could not find a configured source with the \
                               name `{}` when attempting to lookup `{}` \
                               (configuration in `{}`)",
                              name, orig_name, path.display()),
            };
            match cfg.replace_with {
                Some((ref s, ref p)) => {
                    name = s;
                    path = p;
                }
                None if *id == cfg.id => return Ok(id.load(self.config)),
                None => {
                    new_id = cfg.id.with_precise(id.precise()
                                                 .map(|s| s.to_string()));
                    break
                }
            }
            debug!("following pointer to {}", name);
            if name == orig_name {
                bail!("detected a cycle of `replace-with` sources, the source \
                       `{}` is eventually replaced with itself \
                       (configuration in `{}`)", name, path.display())
            }
        }
        let new_src = new_id.load(self.config);
        let old_src = id.load(self.config);
        if new_src.supports_checksums() != old_src.supports_checksums() {
            let (supports, no_support) = if new_src.supports_checksums() {
                (name, orig_name)
            } else {
                (orig_name, name)
            };
            bail!("\
cannot replace `{orig}` with `{name}`, the source `{supports}` supports \
checksums, but `{no_support}` does not

a lock file compatible with `{orig}` cannot be generated in this situation
", orig = orig_name, name = name, supports = supports, no_support = no_support);
        }
        Ok(Box::new(ReplacedSource::new(id, &new_id, new_src)))
    }

    fn add(&mut self, name: &str, cfg: SourceConfig) {
        self.id2name.insert(cfg.id.clone(), name.to_string());
        self.cfgs.insert(name.to_string(), cfg);
    }

    fn add_config(&mut self, name: &str, cfg: &ConfigValue) -> CargoResult<()> {
        let (table, _path) = cfg.table(&format!("source.{}", name))?;
        let mut srcs = Vec::new();
        if let Some(val) = table.get("registry") {
            let url = url(val, &format!("source.{}.registry", name))?;
            srcs.push(SourceId::for_registry(&url));
        }
        if let Some(val) = table.get("local-registry") {
            let (s, path) = val.string(&format!("source.{}.local-registry",
                                                     name))?;
            let mut path = path.to_path_buf();
            path.pop();
            path.pop();
            path.push(s);
            srcs.push(SourceId::for_local_registry(&path)?);
        }
        if let Some(val) = table.get("directory") {
            let (s, path) = val.string(&format!("source.{}.directory",
                                                     name))?;
            let mut path = path.to_path_buf();
            path.pop();
            path.pop();
            path.push(s);
            srcs.push(SourceId::for_directory(&path)?);
        }
        if name == "crates-io" && srcs.is_empty() {
            srcs.push(SourceId::crates_io(self.config)?);
        }

        let mut srcs = srcs.into_iter();
        let src = srcs.next().ok_or_else(|| {
            CargoError::from(format!("no source URL specified for `source.{}`, need \
                                      either `registry` or `local-registry` defined",
                                     name))
        })?;
        if srcs.next().is_some() {
            return Err(format!("more than one source URL specified for \
                                `source.{}`", name).into())
        }

        let mut replace_with = None;
        if let Some(val) = table.get("replace-with") {
            let (s, path) = val.string(&format!("source.{}.replace-with",
                                                     name))?;
            replace_with = Some((s.to_string(), path.to_path_buf()));
        }

        self.add(name, SourceConfig {
            id: src,
            replace_with: replace_with,
        });

        return Ok(());

        fn url(cfg: &ConfigValue, key: &str) -> CargoResult<Url> {
            let (url, path) = cfg.string(key)?;
            url.to_url().chain_err(|| {
                format!("configuration key `{}` specified an invalid \
                         URL (in {})", key, path.display())

            })
        }
    }
}
<|endoftext|>


<commit_before>extern crate minifb;
extern crate bgfx_rs;
extern crate viewdock;

use bgfx_rs::Bgfx;
use libc::{c_void, c_int};
use minifb::{Scale, WindowOptions, MouseMode, MouseButton, Key, KeyRepeat};
use core::view_plugins::{ViewHandle, ViewPlugins, ViewInstance};
use core::session::{Sessions, Session, SessionHandle};
use core::reader_wrapper::ReaderWrapper;
use self::viewdock::{Workspace, Rect, Direction, DockHandle, SplitHandle};
use imgui_sys::Imgui;
use prodbg_api::ui_ffi::{PDVec2};
use prodbg_api::view::CViewCallbacks;

const WIDTH: usize = 1280;
const HEIGHT: usize = 800;

enum State {
    Default,
    DraggingSlider,
}

pub struct MouseState {
    handle: Option<(SplitHandle, Direction)>,
    state: State,
    prev_mouse: (f32, f32)
}

impl MouseState {
    pub fn new() -> MouseState {
        MouseState {
            handle: None,
            state: State::Default,
            prev_mouse: (0.0, 0.0),
        }
    }
}

pub struct Window {
    /// minifb window
    pub win: minifb::Window,

    /// Views in this window
    pub views: Vec<ViewHandle>,

    ///
    pub ws: Workspace,

    pub mouse_state: MouseState,
}

struct WindowState {
    pub showed_popup: u32,
    pub should_close: bool,
}

///! Windows keeps track of all different windows that are present with in the application
///! There are several ways windows can be created:
///!
///! 1. User opens a new window using a shortcut or menu selection.
///! 2. User "undocks" a view from an existing window giving it it's own floating window.
///! 3. etc

pub struct Windows {
    /// All the windows being tracked
    windows: Vec<Window>,
    current: usize,
}

impl Windows {
    pub fn new() -> Windows {
        Windows {
            windows: Vec::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self) {
        if self.windows.len() > 0 {
            return;
        }

        let window = Self::create_window(WIDTH, HEIGHT).expect("Unable to create window");

        self.windows.push(window)
   }

    pub fn create_window(width: usize, height: usize) -> minifb::Result<Window> {
        let res = minifb::Window::new("ProDBG",
                                      width,
                                      height,
                                      WindowOptions {
                                          resize: true,
                                          scale: Scale::X1,
                                          ..WindowOptions::default()
                                      });
        match res {
            Ok(win) => {
                Bgfx::create_window(win.get_window_handle() as *const c_void,
                                    width as c_int,
                                    height as c_int);
                Ok(Window {
                    win: win,
                    views: Vec::new(),
                    mouse_state: MouseState::new(),
                    ws: Workspace::new(Rect::new(0.0, 0.0, width as f32, (height - 20) as f32)).unwrap(),
                })
            }
            Err(err) => Err(err),
        }
    }

    pub fn create_window_with_menus(&mut self) -> minifb::Result<Window> {
        //const WIDTH: usize = 1280;
        //const HEIGHT: usize = 1024;

        let window = try!(Self::create_window(WIDTH, HEIGHT));

        // for menu in &menus {
        // window.add_menu(m.name, m.menu);
        // }
        //

        Ok(window)
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins);

            if !self.windows[i].win.is_open() {
                self.windows.swap_remove(i);
            }
        }
    }

    pub fn get_current(&mut self) -> &mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.len() == 0
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save(_filename: &str) {}

    /// Load the state of all the views from a previous run
    pub fn load(_filename: &str) {}
}

impl Window {
    fn is_inside(v: (f32, f32), pos: PDVec2, size: PDVec2) -> bool {
        let x0 = pos.x;
        let y0 = pos.y;
        let x1 = pos.x + size.x;
        let y1 = pos.y + size.y;

        if (v.0 >= x0 && v.0 < x1) && (v.1 >= y0 && v.1 < y1) {
            true
        } else {
            false
        }
    }

    fn update_view(&self, instance: &mut ViewInstance, session: &mut Session, show_context_menu: bool, mouse: (f32, f32)) -> WindowState {
        let ui = instance.ui;

        if let Some(rect) = self.ws.get_rect_by_handle(DockHandle(instance.handle.0)) {
            Imgui::set_window_pos(rect.x, rect.y);
            Imgui::set_window_size(rect.width, rect.height);
        }

        let open = Imgui::begin_window(&instance.name, true);
        Imgui::init_state(ui.api);

        let pos = ui.get_window_pos();
        let size = ui.get_window_size();

        if Self::is_inside(mouse, pos, size) && show_context_menu {
            Imgui::mark_show_popup(ui.api, true);
        } else {
            Imgui::mark_show_popup(ui.api, false);
        }

        // Make sure we move the cursor to the start of the stream here
        ReaderWrapper::reset_reader(&mut session.reader);

        unsafe {
            let plugin_funcs = instance.plugin_type.plugin_funcs as *mut CViewCallbacks;
            ((*plugin_funcs).update.unwrap())(instance.plugin_data,
                                                ui.api as *mut c_void,
                                                session.reader.api as *mut c_void,
                                                session.get_current_writer().api as *mut c_void);
        }

        let has_shown_menu = Imgui::has_showed_popup(ui.api);

        Imgui::end_window();

        WindowState {
            showed_popup: has_shown_menu,
            should_close: !open,
        }
    }

    pub fn remove_views(&mut self, view_plugins: &mut ViewPlugins, views: &Vec<ViewHandle>) {
        for view in views {
            view_plugins.destroy_instance(*view);
            //println!("------------------ before delete ----------------------------");
            //self.ws.dump_tree();
            self.ws.delete_by_handle(DockHandle(view.0));
            //println!("------------------ after delete ----------------------------");
            //self.ws.dump_tree();
        }
    }
    /*
    CursorType_Default,
    CursorType_SizeHorizontal,
    CursorType_SizeVertical,
    */

    fn update_mouse_state(&mut self, mouse_pos: (f32, f32)) {
        match self.mouse_state.state {
            State::Default => {
                if let Some(h) = self.ws.is_hovering_sizer(mouse_pos) {
                    if h.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }

                    if self.win.get_mouse_down(MouseButton::Left) {
                        self.mouse_state.handle = Some(h);
                        self.mouse_state.state = State::DraggingSlider;
                    }
                } else {
                    Bgfx::cursor_set_type(0);
                }
            },

            State::DraggingSlider => {
                let pm = self.mouse_state.prev_mouse;
                let delta = (pm.0 - mouse_pos.0, pm.1 - mouse_pos.1);

                if self.win.get_mouse_down(MouseButton::Left) {
                    let t = self.mouse_state.handle.unwrap();
                    if t.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }
                    self.ws.drag_sizer(t.0, delta);
                } else {
                    self.mouse_state.handle = None;
                    self.mouse_state.state = State::Default;
                    Bgfx::cursor_set_type(0);
                }
            }
        }

        /*
        if let Some(handle) = ws.is_hovering_sizer(mouse_pos) {
            let delta = (prev_mouse.0 - mouse_pos.0, prev_mouse.1 - mouse_pos.1);

            if window.get_mouse_down(MouseButton::Left) {
                println!("drangging sizer");
                ws.drag_sizer(handle, delta);
            }
        }
        */

        self.mouse_state.prev_mouse = mouse_pos;
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        let mut views_to_delete = Vec::new();
        let mut has_shown_menu = 0u32;

        self.win.update();
        self.ws.update();

        let mouse = self.win.get_mouse_pos(MouseMode::Clamp).unwrap_or((0.0, 0.0));

        self.update_mouse_state(mouse);

        Bgfx::set_mouse_pos(mouse);
        Bgfx::set_mouse_state(0, self.win.get_mouse_down(MouseButton::Left));

        let show_context_menu = self.win.get_mouse_down(MouseButton::Right);

        for view in &self.views {
            if let Some(ref mut v) = view_plugins.get_view(*view) {
                if let Some(ref mut s) = sessions.get_session(v.session_handle) {
                    let state = Self::update_view(self, v, s, show_context_menu, mouse);

                    if state.should_close {
                        views_to_delete.push(*view);
                    }

                    has_shown_menu |= state.showed_popup;
                }
            }
        }

        if self.win.is_key_pressed(Key::Down, KeyRepeat::No) {
            self.ws.dump_tree();
        }

        if self.win.is_key_pressed(Key::Up, KeyRepeat::No) {
            let _ = self.ws.save("/Users/danielcollin/code/temp/test.xml");
        }

        if self.win.is_key_pressed(Key::Right, KeyRepeat::No) {
            let ws = Workspace::load("/Users/danielcollin/code/temp/test.xml").unwrap();
            let docks = ws.get_docks();
            self.views.clear();

            for dock in &docks {
                //println!("create stuff... {} - {}", dock.name, dock.handle.0);
                let ui = Imgui::create_ui_instance();
                let handle = ViewHandle(dock.handle.0);
                if dock.name == "" {
                    view_plugins.create_instance_with_handle(ui, &"Bitmap View".to_owned(), SessionHandle(0), ViewHandle(dock.handle.0));
                } else {
                    view_plugins.create_instance_with_handle(ui, &dock.name, SessionHandle(0), ViewHandle(dock.handle.0));
                }
                self.views.push(handle);
            }

            self.ws = ws;
        }

        // if now plugin has showed a menu we do it here
        // TODO: Handle diffrent cases when attach menu on to plugin menu or not

        if has_shown_menu == 0 && show_context_menu {
            Self::show_popup(self, true, mouse, view_plugins);
        } else {
            Self::show_popup(self, false, mouse, view_plugins);
        }

        Self::remove_views(self, view_plugins, &views_to_delete);
    }

    fn split_view(&mut self, name: &String, view_plugins: &mut ViewPlugins, pos: (f32, f32), direction: Direction) {
        let ui = Imgui::create_ui_instance();
        if let Some(handle) = view_plugins.create_instance(ui, name, SessionHandle(0)) {
            if let Some(dock_handle) = self.ws.get_hover_dock(pos) {
                let new_handle = DockHandle(handle.0);
                self.ws.split_by_dock_handle(direction, dock_handle, new_handle);
                self.ws.set_name_to_handle(name, new_handle);
                //self.ws.dump_tree_linear();
            } else {
                self.ws.new_split(DockHandle(handle.0), direction);
                //println!("no split");
            }

            self.views.push(handle);
        }
    }

    fn show_popup(&mut self, show: bool, mouse_pos: (f32, f32), view_plugins: &mut ViewPlugins) {
        let ui = Imgui::get_ui();

        if show {
            ui.open_popup("plugins");
        }

        if ui.begin_popup("plugins") {
            let plugin_names = view_plugins.get_plugin_names();

            if ui.begin_menu("Split Horizontally", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Horizontal);
                    }
                }
                ui.end_menu();
            }

            if ui.begin_menu("Split Vertically", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Vertical);
                    }
                }
                ui.end_menu();
            }

            ui.end_popup();
        }
    }
}
<commit_msg>Some cleanup<commit_after>extern crate minifb;
extern crate bgfx_rs;
extern crate viewdock;

use bgfx_rs::Bgfx;
use libc::{c_void, c_int};
use minifb::{Scale, WindowOptions, MouseMode, MouseButton, Key, KeyRepeat};
use core::view_plugins::{ViewHandle, ViewPlugins, ViewInstance};
use core::session::{Sessions, Session, SessionHandle};
use core::reader_wrapper::ReaderWrapper;
use self::viewdock::{Workspace, Rect, Direction, DockHandle, SplitHandle};
use imgui_sys::Imgui;
use prodbg_api::ui_ffi::{PDVec2};
use prodbg_api::view::CViewCallbacks;

const WIDTH: usize = 1280;
const HEIGHT: usize = 800;

enum State {
    Default,
    DraggingSlider,
}

pub struct MouseState {
    handle: Option<(SplitHandle, Direction)>,
    state: State,
    prev_mouse: (f32, f32)
}

impl MouseState {
    pub fn new() -> MouseState {
        MouseState {
            handle: None,
            state: State::Default,
            prev_mouse: (0.0, 0.0),
        }
    }
}

pub struct Window {
    /// minifb window
    pub win: minifb::Window,

    /// Views in this window
    pub views: Vec<ViewHandle>,

    ///
    pub ws: Workspace,

    pub mouse_state: MouseState,
}

struct WindowState {
    pub showed_popup: u32,
    pub should_close: bool,
}

///! Windows keeps track of all different windows that are present with in the application
///! There are several ways windows can be created:
///!
///! 1. User opens a new window using a shortcut or menu selection.
///! 2. User "undocks" a view from an existing window giving it it's own floating window.
///! 3. etc

pub struct Windows {
    /// All the windows being tracked
    windows: Vec<Window>,
    current: usize,
}

impl Windows {
    pub fn new() -> Windows {
        Windows {
            windows: Vec::new(),
            current: 0,
        }
    }

    /// Create a default window which will only be created if there are no other
    pub fn create_default(&mut self) {
        if self.windows.len() > 0 {
            return;
        }

        let window = Self::create_window(WIDTH, HEIGHT).expect("Unable to create window");

        self.windows.push(window)
   }

    pub fn create_window(width: usize, height: usize) -> minifb::Result<Window> {
        let res = minifb::Window::new("ProDBG",
                                      width,
                                      height,
                                      WindowOptions {
                                          resize: true,
                                          scale: Scale::X1,
                                          ..WindowOptions::default()
                                      });
        match res {
            Ok(win) => {
                Bgfx::create_window(win.get_window_handle() as *const c_void,
                                    width as c_int,
                                    height as c_int);
                Ok(Window {
                    win: win,
                    views: Vec::new(),
                    mouse_state: MouseState::new(),
                    ws: Workspace::new(Rect::new(0.0, 0.0, width as f32, (height - 20) as f32)).unwrap(),
                })
            }
            Err(err) => Err(err),
        }
    }

    pub fn create_window_with_menus(&mut self) -> minifb::Result<Window> {
        //const WIDTH: usize = 1280;
        //const HEIGHT: usize = 1024;

        let window = try!(Self::create_window(WIDTH, HEIGHT));

        // for menu in &menus {
        // window.add_menu(m.name, m.menu);
        // }
        //

        Ok(window)
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        for i in (0..self.windows.len()).rev() {
            self.windows[i].update(sessions, view_plugins);

            if !self.windows[i].win.is_open() {
                self.windows.swap_remove(i);
            }
        }
    }

    pub fn get_current(&mut self) -> &mut Window {
        let current = self.current;
        &mut self.windows[current]
    }

    /// Checks if application should exit (all window instances closed)
    pub fn should_exit(&self) -> bool {
        self.windows.len() == 0
    }

    /// Save the state of the windows (usually done when exiting the application)
    pub fn save(_filename: &str) {}

    /// Load the state of all the views from a previous run
    pub fn load(_filename: &str) {}
}

impl Window {
    fn is_inside(v: (f32, f32), pos: PDVec2, size: PDVec2) -> bool {
        let x0 = pos.x;
        let y0 = pos.y;
        let x1 = pos.x + size.x;
        let y1 = pos.y + size.y;

        if (v.0 >= x0 && v.0 < x1) && (v.1 >= y0 && v.1 < y1) {
            true
        } else {
            false
        }
    }

    fn update_view(&self, instance: &mut ViewInstance, session: &mut Session, show_context_menu: bool, mouse: (f32, f32)) -> WindowState {
        let ui = instance.ui;

        if let Some(rect) = self.ws.get_rect_by_handle(DockHandle(instance.handle.0)) {
            Imgui::set_window_pos(rect.x, rect.y);
            Imgui::set_window_size(rect.width, rect.height);
        }

        let open = Imgui::begin_window(&instance.name, true);
        Imgui::init_state(ui.api);

        let pos = ui.get_window_pos();
        let size = ui.get_window_size();

        if Self::is_inside(mouse, pos, size) && show_context_menu {
            Imgui::mark_show_popup(ui.api, true);
        } else {
            Imgui::mark_show_popup(ui.api, false);
        }

        // Make sure we move the cursor to the start of the stream here
        ReaderWrapper::reset_reader(&mut session.reader);

        unsafe {
            let plugin_funcs = instance.plugin_type.plugin_funcs as *mut CViewCallbacks;
            ((*plugin_funcs).update.unwrap())(instance.plugin_data,
                                                ui.api as *mut c_void,
                                                session.reader.api as *mut c_void,
                                                session.get_current_writer().api as *mut c_void);
        }

        let has_shown_menu = Imgui::has_showed_popup(ui.api);

        Imgui::end_window();

        WindowState {
            showed_popup: has_shown_menu,
            should_close: !open,
        }
    }

    pub fn remove_views(&mut self, view_plugins: &mut ViewPlugins, views: &Vec<ViewHandle>) {
        for view in views {
            view_plugins.destroy_instance(*view);
            self.ws.delete_by_handle(DockHandle(view.0));
        }
    }

    fn update_mouse_state(&mut self, mouse_pos: (f32, f32)) {
        match self.mouse_state.state {
            State::Default => {
                if let Some(h) = self.ws.is_hovering_sizer(mouse_pos) {
                    if h.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }

                    if self.win.get_mouse_down(MouseButton::Left) {
                        self.mouse_state.handle = Some(h);
                        self.mouse_state.state = State::DraggingSlider;
                    }
                } else {
                    Bgfx::cursor_set_type(0);
                }
            },

            State::DraggingSlider => {
                let pm = self.mouse_state.prev_mouse;
                let delta = (pm.0 - mouse_pos.0, pm.1 - mouse_pos.1);

                if self.win.get_mouse_down(MouseButton::Left) {
                    let t = self.mouse_state.handle.unwrap();
                    if t.1 == Direction::Vertical {
                        Bgfx::cursor_set_type(2);
                    } else {
                        Bgfx::cursor_set_type(1);
                    }
                    self.ws.drag_sizer(t.0, delta);
                } else {
                    self.mouse_state.handle = None;
                    self.mouse_state.state = State::Default;
                    Bgfx::cursor_set_type(0);
                }
            }
        }

        /*
        if let Some(handle) = ws.is_hovering_sizer(mouse_pos) {
            let delta = (prev_mouse.0 - mouse_pos.0, prev_mouse.1 - mouse_pos.1);

            if window.get_mouse_down(MouseButton::Left) {
                println!("drangging sizer");
                ws.drag_sizer(handle, delta);
            }
        }
        */

        self.mouse_state.prev_mouse = mouse_pos;
    }

    pub fn update(&mut self, sessions: &mut Sessions, view_plugins: &mut ViewPlugins) {
        let mut views_to_delete = Vec::new();
        let mut has_shown_menu = 0u32;

        self.win.update();
        self.ws.update();

        let mouse = self.win.get_mouse_pos(MouseMode::Clamp).unwrap_or((0.0, 0.0));

        self.update_mouse_state(mouse);

        Bgfx::set_mouse_pos(mouse);
        Bgfx::set_mouse_state(0, self.win.get_mouse_down(MouseButton::Left));

        let show_context_menu = self.win.get_mouse_down(MouseButton::Right);

        for view in &self.views {
            if let Some(ref mut v) = view_plugins.get_view(*view) {
                if let Some(ref mut s) = sessions.get_session(v.session_handle) {
                    let state = Self::update_view(self, v, s, show_context_menu, mouse);

                    if state.should_close {
                        views_to_delete.push(*view);
                    }

                    has_shown_menu |= state.showed_popup;
                }
            }
        }

        if self.win.is_key_pressed(Key::Down, KeyRepeat::No) {
            self.ws.dump_tree();
        }

        if self.win.is_key_pressed(Key::Up, KeyRepeat::No) {
            let _ = self.ws.save("/Users/danielcollin/code/temp/test.xml");
        }

        if self.win.is_key_pressed(Key::Right, KeyRepeat::No) {
            let ws = Workspace::load("/Users/danielcollin/code/temp/test.xml").unwrap();
            let docks = ws.get_docks();
            self.views.clear();

            for dock in &docks {
                //println!("create stuff... {} - {}", dock.name, dock.handle.0);
                let ui = Imgui::create_ui_instance();
                let handle = ViewHandle(dock.handle.0);
                if dock.name == "" {
                    view_plugins.create_instance_with_handle(ui, &"Bitmap View".to_owned(), SessionHandle(0), ViewHandle(dock.handle.0));
                } else {
                    view_plugins.create_instance_with_handle(ui, &dock.name, SessionHandle(0), ViewHandle(dock.handle.0));
                }
                self.views.push(handle);
            }

            self.ws = ws;
        }

        // if now plugin has showed a menu we do it here
        // TODO: Handle diffrent cases when attach menu on to plugin menu or not

        if has_shown_menu == 0 && show_context_menu {
            Self::show_popup(self, true, mouse, view_plugins);
        } else {
            Self::show_popup(self, false, mouse, view_plugins);
        }

        Self::remove_views(self, view_plugins, &views_to_delete);
    }

    fn split_view(&mut self, name: &String, view_plugins: &mut ViewPlugins, pos: (f32, f32), direction: Direction) {
        let ui = Imgui::create_ui_instance();
        if let Some(handle) = view_plugins.create_instance(ui, name, SessionHandle(0)) {
            if let Some(dock_handle) = self.ws.get_hover_dock(pos) {
                let new_handle = DockHandle(handle.0);
                self.ws.split_by_dock_handle(direction, dock_handle, new_handle);
                self.ws.set_name_to_handle(name, new_handle);
                //self.ws.dump_tree_linear();
            } else {
                self.ws.new_split(DockHandle(handle.0), direction);
                //println!("no split");
            }

            self.views.push(handle);
        }
    }

    fn show_popup(&mut self, show: bool, mouse_pos: (f32, f32), view_plugins: &mut ViewPlugins) {
        let ui = Imgui::get_ui();

        if show {
            ui.open_popup("plugins");
        }

        if ui.begin_popup("plugins") {
            let plugin_names = view_plugins.get_plugin_names();

            if ui.begin_menu("Split Horizontally", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Horizontal);
                    }
                }
                ui.end_menu();
            }

            if ui.begin_menu("Split Vertically", true) {
                for name in &plugin_names {
                    if ui.menu_item(name, false, true) {
                        Self::split_view(self, &name, view_plugins, mouse_pos, Direction::Vertical);
                    }
                }
                ui.end_menu();
            }

            ui.end_popup();
        }
    }
}
<|endoftext|>


<commit_before>use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Storage, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;

/// A VM state without PC.
pub struct State<M, S> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState<S>,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M, S> State<M, S> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M, S> {
    state: State<M, S>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
pub enum MachineStatus {
    Running,
    ExitedOk,
    ExitedErr(MachineError),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default, S: Storage + Default + Clone> Machine<M, S> {
    pub fn new(context: Context, block: BlockHeader, patch: Patch, depth: usize) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: block,
                patch: patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: AccountState::default(),
                blockhash_state: BlockhashState::default(),
                logs: Vec::new(),

                depth: depth,
            },
        }
    }

    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn commit_account(&mut self, commitment: AccountCommitment<S>) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    #[allow(unused_variables)]
    pub fn apply_sub(&mut self, sub: Machine<M, S>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M, S>) {
        match sub.status() {
            MachineStatus::ExitedOk => {
                if self.state.available_gas() < sub.state.used_gas {
                    panic!();
                }

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.create(sub.state.context.address,
                                                sub.state.context.value,
                                                sub.state.out.as_slice());
            },
            MachineStatus::ExitedErr(_) => {
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M, S>, out_start: M256, out_len: M256) {
        match sub.status() {
            MachineStatus::ExitedOk => {
                if self.state.available_gas() < sub.state.used_gas {
                    panic!();
                }

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);
        let after_gas = self.state.context.gas_limit - memory_gas - self.state.used_gas - gas_cost + gas_stipend;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        if self.state.context.gas_limit < memory_gas + self.state.used_gas + gas_cost - gas_stipend {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    pub fn state(&self) -> &State<M, S> {
        &self.state
    }

    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<commit_msg>Problem: gas should always be deducted Solution: add the logic<commit_after>use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Storage, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;

/// A VM state without PC.
pub struct State<M, S> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState<S>,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M, S> State<M, S> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M, S> {
    state: State<M, S>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
pub enum MachineStatus {
    Running,
    ExitedOk,
    ExitedErr(MachineError),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default, S: Storage + Default + Clone> Machine<M, S> {
    pub fn new(context: Context, block: BlockHeader, patch: Patch, depth: usize) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: block,
                patch: patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: AccountState::default(),
                blockhash_state: BlockhashState::default(),
                logs: Vec::new(),

                depth: depth,
            },
        }
    }

    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn commit_account(&mut self, commitment: AccountCommitment<S>) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    #[allow(unused_variables)]
    pub fn apply_sub(&mut self, sub: Machine<M, S>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M, S>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.create(sub.state.context.address,
                                                sub.state.context.value,
                                                sub.state.out.as_slice());
            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M, S>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);
        let after_gas = self.state.context.gas_limit - memory_gas - self.state.used_gas - gas_cost + gas_stipend;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        if self.state.context.gas_limit < memory_gas + self.state.used_gas + gas_cost - gas_stipend {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    pub fn state(&self) -> &State<M, S> {
        &self.state
    }

    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<|endoftext|>