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

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLength { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLength {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLength::Ub => write!(f, "UB"),
            OffsetLength::Sb => write!(f, "SB"),
            OffsetLength::Uw => write!(f, "UW"),
            OffsetLength::Sw => write!(f, "SW"),
            OffsetLength::Ud => write!(f, "UD"),
            OffsetLength::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLength {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLength, io::Error> {
        match s {
            "UB" => Ok(OffsetLength::Ub),
            "SB" => Ok(OffsetLength::Sb),
            "UW" => Ok(OffsetLength::Uw),
            "SW" => Ok(OffsetLength::Sw),
            "UD" => Ok(OffsetLength::Ud),
            "SD" => Ok(OffsetLength::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { address: OffsetAddr, length: OffsetLength, value: i64 }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(addr: OffsetAddr, len: OffsetLength, value: i64) -> Message {
        Message::WriteOffset { address: addr, length: len, value: value }
    }

    pub fn decode<R: io::BufRead>(r: &mut R) -> io::Result<Message> {
        let mut line = String::new();
        try!(r.read_line(&mut line));
        let mut split = line.split_whitespace();
        let cmd = try!(split.next().ok_or(Message::input_error(&line)));
        match &cmd.to_uppercase()[..] {
            "BEGIN" => Message::decode_begin(&line, &mut split),
            "WRITE_LVAR" => Message::decode_write_lvar(&line, &mut split),
            "WRITE_OFFSET" => Message::decode_write_offset(&line, &mut split),
            _ => Err(Message::input_error(&line)),
        }
    }

    pub fn encode<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(w, "BEGIN {} {}\n", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(w, "WRITE_LVAR {} {}\n", lvar, value),
            &Message::WriteOffset { ref address, ref length, value } =>
                write!(w, "WRITE_OFFSET {}:{} {}\n", address, length, value),
        }
    }

    fn decode_begin<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let version = try!(args.next().ok_or(Message::input_error(line)));
        let client_id = try!(args.next().ok_or(Message::input_error(line)));
        let version = try!(version.parse().map_err(|_| Message::input_error(line)));
        Ok(Message::begin(version, &client_id))
    }

    fn decode_write_lvar<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let lvar = try!(args.next().ok_or(Message::input_error(line)));
        let value = try!(args.next().ok_or(Message::input_error(line)));
        let value = try!(value.parse().map_err(|_| Message::input_error(line)));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn decode_write_offset<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let error = || Message::input_error(line);
        let mut offset = try!(args.next().ok_or_else(&error)).split(":");
        let addr = try!(offset.next().ok_or_else(&error));
        let addr: OffsetAddr = try!(OffsetAddr::from_hex(&addr).map_err(|_| error()));
        let len = try!(offset.next().ok_or_else(&error));
        let len = try!(len.parse().map_err(|_| error()));
        let value = try!(args.next().ok_or_else(&error));
        let value = try!(value.parse().map_err(|_| error()));
        Ok(Message::write_offset(addr, len, value))
    }

    fn input_error(line: &str) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", line))
    }
}

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

    #[test]
    fn should_encode_begin_msg() {
        let mut buf = vec![];
        let msg = Message::begin(1, "arduino");
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"BEGIN 1 arduino\n")
    }

    #[test]
    fn should_decode_begin_msg() {
        let mut buf = &b"BEGIN 1 arduino\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_encode_write_lvar_msg() {
        let mut buf = vec![];
        let msg = Message::write_lvar("foobar", 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_LVAR foobar 42\n")
    }

    #[test]
    fn should_decode_write_lvar_msg() {
        let mut buf = &b"WRITE_LVAR foobar 42\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_encode_write_offset_msg() {
        let mut buf = vec![];
        let msg = Message::write_offset(OffsetAddr(0x1234), OffsetLength::Uw, 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_OFFSET 1234:UW 42\n")
    }

    #[test]
    fn should_decode_write_offset_msg() {
        let mut buf = &b"WRITE_OFFSET 1234:UW 42\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::write_offset(OffsetAddr(0x1234), OffsetLength::Uw, 42));
    }
}
<commit_msg>Use lazy eval for error handling in `oacsp` module<commit_after>//
// FlightVars
// Copyright (c) 2015, 2016 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::io;
use std::str::FromStr;

use byteorder::{BigEndian, ReadBytesExt};
use hex::FromHex;

#[derive(Debug, PartialEq)]
pub struct OffsetAddr(u16);

impl FromHex for OffsetAddr {
    type Error = io::Error;
    fn from_hex(s: &str) -> Result<Self, Self::Error> {
        let error = || io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid FSUIPC offset address in '{}'", s));
        let buf: Vec<u8> = try!(FromHex::from_hex(s).map_err(|_| error()));
        if buf.len() > 2 { Err(error()) }
        else {
            (&buf[..]).read_u16::<BigEndian>()
                .map(|v| OffsetAddr(v))
                .map_err(|_| error())
        }
    }
}

impl fmt::Display for OffsetAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "{:x}", self.0)
    }
}

#[derive(Debug, PartialEq)]
pub enum OffsetLength { Ub, Sb, Uw, Sw, Ud, Sd }

impl fmt::Display for OffsetLength {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            OffsetLength::Ub => write!(f, "UB"),
            OffsetLength::Sb => write!(f, "SB"),
            OffsetLength::Uw => write!(f, "UW"),
            OffsetLength::Sw => write!(f, "SW"),
            OffsetLength::Ud => write!(f, "UD"),
            OffsetLength::Sd => write!(f, "SD"),
        }
    }
}

impl FromStr for OffsetLength {
    type Err = io::Error;
    fn from_str(s: &str) -> Result<OffsetLength, io::Error> {
        match s {
            "UB" => Ok(OffsetLength::Ub),
            "SB" => Ok(OffsetLength::Sb),
            "UW" => Ok(OffsetLength::Uw),
            "SW" => Ok(OffsetLength::Sw),
            "UD" => Ok(OffsetLength::Ud),
            "SD" => Ok(OffsetLength::Sd),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("invalid FSUIPC offset length in '{}'", s))),
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum Message {
    Begin { version: u16, client_id: String },
    WriteLvar { lvar: String, value: i64 },
    WriteOffset { address: OffsetAddr, length: OffsetLength, value: i64 }
}

impl Message {

    pub fn begin(version: u16, client_id: &str) -> Message {
        Message::Begin { version: version, client_id: client_id.to_string() }
    }

    pub fn write_lvar(lvar: &str, value: i64) -> Message {
        Message::WriteLvar { lvar: lvar.to_string(), value: value }
    }

    pub fn write_offset(addr: OffsetAddr, len: OffsetLength, value: i64) -> Message {
        Message::WriteOffset { address: addr, length: len, value: value }
    }

    pub fn decode<R: io::BufRead>(r: &mut R) -> io::Result<Message> {
        let mut line = String::new();
        try!(r.read_line(&mut line));
        let mut split = line.split_whitespace();
        let cmd = try!(split.next().ok_or(Message::input_error(&line)));
        match &cmd.to_uppercase()[..] {
            "BEGIN" => Message::decode_begin(&line, &mut split),
            "WRITE_LVAR" => Message::decode_write_lvar(&line, &mut split),
            "WRITE_OFFSET" => Message::decode_write_offset(&line, &mut split),
            _ => Err(Message::input_error(&line)),
        }
    }

    pub fn encode<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            &Message::Begin { version, ref client_id } =>
                write!(w, "BEGIN {} {}\n", version, client_id),
            &Message::WriteLvar { ref lvar, value} =>
                write!(w, "WRITE_LVAR {} {}\n", lvar, value),
            &Message::WriteOffset { ref address, ref length, value } =>
                write!(w, "WRITE_OFFSET {}:{} {}\n", address, length, value),
        }
    }

    fn decode_begin<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let error = || Message::input_error(line);
        let version = try!(args.next().ok_or_else(&error));
        let client_id = try!(args.next().ok_or_else(&error));
        let version = try!(version.parse().map_err(|_| error()));
        Ok(Message::begin(version, &client_id))
    }

    fn decode_write_lvar<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let error = || Message::input_error(line);
        let lvar = try!(args.next().ok_or_else(&error));
        let value = try!(args.next().ok_or_else(&error));
        let value = try!(value.parse().map_err(|_| error()));
        Ok(Message::write_lvar(&lvar, value))
    }

    fn decode_write_offset<'a, I: Iterator<Item=&'a str>>(
            line: &str, args: &mut I) -> io::Result<Message> {
        let error = || Message::input_error(line);
        let mut offset = try!(args.next().ok_or_else(&error)).split(":");
        let addr = try!(offset.next().ok_or_else(&error));
        let addr: OffsetAddr = try!(OffsetAddr::from_hex(&addr).map_err(|_| error()));
        let len = try!(offset.next().ok_or_else(&error));
        let len = try!(len.parse().map_err(|_| error()));
        let value = try!(args.next().ok_or_else(&error));
        let value = try!(value.parse().map_err(|_| error()));
        Ok(Message::write_offset(addr, len, value))
    }

    fn input_error(line: &str) -> io::Error {
        io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("invalid oacsp message in '{}'", line))
    }
}

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

    #[test]
    fn should_encode_begin_msg() {
        let mut buf = vec![];
        let msg = Message::begin(1, "arduino");
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"BEGIN 1 arduino\n")
    }

    #[test]
    fn should_decode_begin_msg() {
        let mut buf = &b"BEGIN 1 arduino\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::begin(1, "arduino"));
    }

    #[test]
    fn should_encode_write_lvar_msg() {
        let mut buf = vec![];
        let msg = Message::write_lvar("foobar", 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_LVAR foobar 42\n")
    }

    #[test]
    fn should_decode_write_lvar_msg() {
        let mut buf = &b"WRITE_LVAR foobar 42\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::write_lvar("foobar", 42));
    }

    #[test]
    fn should_encode_write_offset_msg() {
        let mut buf = vec![];
        let msg = Message::write_offset(OffsetAddr(0x1234), OffsetLength::Uw, 42);
        msg.encode(&mut buf).unwrap();
        assert_eq!(buf, b"WRITE_OFFSET 1234:UW 42\n")
    }

    #[test]
    fn should_decode_write_offset_msg() {
        let mut buf = &b"WRITE_OFFSET 1234:UW 42\n"[..];
        let msg = Message::decode(&mut buf).unwrap();
        assert_eq!(msg, Message::write_offset(OffsetAddr(0x1234), OffsetLength::Uw, 42));
    }
}
<|endoftext|>


<commit_before>use std::ptr::RawPtr;
use std::mem;
use std::cell::RefCell;

pub struct Gc<T> {
    gc: RefCell<Gc_<T>>
}
struct Gc_<T> {
    values: Option<Box<GcHeader<T>>>,
    allocated_objects: uint,
    collect_limit: uint
}

#[deriving(Clone, PartialEq)]
struct GcHeader<T> {
    next: Option<Box<GcHeader<T>>>,
    marked: bool,
    value: T
}

pub struct GcPtr<T> {
    ptr: *mut T
}

impl <T> Deref<T> for GcPtr<T> {
    fn deref(&self) -> &T {
        unsafe { & *self.ptr }
    }
}

impl <T> DerefMut<T> for GcPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

pub trait Traverseable<T> {
    fn traverse(&mut self, func: |&mut T|);
}

impl <T: Traverseable<T>> Gc<T> {

    pub fn new() -> Gc<T> {
        Gc { gc: RefCell::new(Gc_ { values: None, allocated_objects: 0, collect_limit: 100 }) }
    }
    pub fn alloc_and_collect<R: Traverseable<T>>(&self, roots: &mut R, value: T) -> GcPtr<T> {
        let ptr = self.gc.borrow_mut().alloc_and_collect(roots, value);
        GcPtr { ptr: ptr }
    }
    pub fn alloc(&self, value: T) -> GcPtr<T> {
        let ptr = self.gc.borrow_mut().alloc(value);
        GcPtr { ptr: ptr }
    }

    pub fn collect<R: Traverseable<T>>(&self, roots: &mut R) {
        self.gc.borrow_mut().collect(roots);
    }
}
impl <T: Traverseable<T>> Gc_<T> {

    fn alloc_and_collect<R: Traverseable<T>>(&mut self, roots: &mut R, value: T) -> *mut T {
        if self.allocated_objects >= self.collect_limit {
            self.collect(roots);
        }
        self.alloc(value)
    }
    fn alloc(&mut self, value: T) -> *mut T {
        self.values = Some(box GcHeader { next: self.values.take(), marked: false, value: value });
        self.allocated_objects += 1;
        &mut self.values.as_mut().unwrap().value
    }

    fn collect<R: Traverseable<T>>(&mut self, roots: &mut R) {
        roots.traverse(|v| self.mark(v));
        self.sweep();
    }

    fn gc_header(value: &mut T) -> &mut GcHeader<T> {
        unsafe {
            let p: *mut u8 = mem::transmute(&mut *value);
            let header = p.offset(mem::size_of::<T>() as int - mem::size_of::<GcHeader<T>>() as int);
            mem::transmute(header)
        }
    }

    fn mark(&mut self, value: &mut T) {
        let header = Gc_::gc_header(value);
        if !header.marked {
            header.marked = true;
            header.value.traverse(|child| self.mark(child));
        }
    }

    fn sweep(&mut self) {
        //Usage of unsafe are sadly needed to circumvent the borrow checker
        let mut first = self.values.take();
        {
            let mut maybe_header = &mut first;
            loop {
                let current: &mut Option<Box<GcHeader<T>>> = unsafe { mem::transmute(&*maybe_header) };
                maybe_header = match *maybe_header {
                    Some(ref mut header) => {
                        if !header.marked {
                            let unreached = mem::replace(current, header.next.take());
                            self.free(unreached);
                            continue
                        }
                        else {
                            header.marked = false;
                            let next: &mut Option<Box<GcHeader<T>>> = unsafe { mem::transmute(&mut header.next) };
                            next
                        }
                    }
                    None => break
                };
            }
        }
        self.values = first;
    }
    fn free(&mut self, header: Option<Box<GcHeader<T>>>) {
        self.allocated_objects -= 1;
        drop(header);
    }
}

#[cfg(test)]
mod tests {
    use super::{Gc, Gc_, GcPtr, GcHeader, Traverseable};
    use std::fmt;

    use self::Value::*;

    struct Data_ {
        fields: GcPtr<Vec<Value>>
    }
    impl  Deref<Vec<Value>> for Data_ {
        fn deref(&self) -> &Vec<Value> {
            &*self.fields
        }
    }
    impl  DerefMut<Vec<Value>> for Data_ {
        fn deref_mut(&mut self) -> &mut Vec<Value> {
            &mut *self.fields
        }
    }
    impl  PartialEq for Data_ {
        fn eq(&self, other: &Data_) -> bool {
            self.fields.ptr == other.fields.ptr
        }
    }
    impl  fmt::Show for Data_ {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            self.fields.ptr.fmt(f)
        }
    }

    #[deriving(PartialEq, Show)]
    enum Value {
        Int(int),
        Data(Data_)
    }
    impl  Traverseable<Vec<Value>> for Vec<Value> {
        fn traverse(&mut self, func: |&mut Vec<Value>|) {
            for v in self.iter_mut() {
                match *v {
                    Data(ref mut data) => func(&mut **data),
                    _ => ()
                }
            }
        }
    }
    impl  Traverseable<Vec<Value>> for Value {
        fn traverse(&mut self, func: |&mut Vec<Value>|) {
            match *self {
                Data(ref mut data) => func(&mut **data),
                _ => ()
            }
        }
    }

    fn num_objects<T>(gc: &Gc<T>) -> uint {
        let gc = gc.gc.borrow();
        let mut header: &GcHeader<T> = match gc.values {
            Some(ref x) => &**x,
            None => return 0
        };
        let mut count = 1;
        loop {
            match header.next {
                Some(ref ptr) => {
                    count += 1;
                    header = &**ptr;
                }
                None => break
            }
        }
        count
    }

    fn new_data(p: GcPtr<Vec<Value>>) -> Value {
        Data(Data_ { fields: p })
    }

    #[test]
    fn gc_header() {
        let gc: Gc<Vec<Value>> = Gc::new();
        let mut ptr = gc.alloc(Vec::new());
        let header: *mut _ = &mut *Gc_::gc_header(&mut *ptr);
        let other: *mut _ = &mut **gc.gc.borrow_mut().values.as_mut().unwrap();
        assert_eq!(header, other);
    }

    #[test]
    fn basic() {
        let gc: Gc<Vec<Value>> = Gc::new();
        let mut stack: Vec<Value> = Vec::new();
        stack.push(new_data(gc.alloc(vec![Int(1)])));
        let d2 = new_data(gc.alloc(vec![stack[0]]));
        stack.push(d2);
        assert_eq!(num_objects(&gc), 2);
        gc.collect(&mut stack);
        assert_eq!(num_objects(&gc), 2);
        match stack[0] {
            Data(ref data) => assert_eq!((**data)[0], Int(1)),
            _ => panic!()
        }
        match stack[1] {
            Data(ref data) => assert_eq!((**data)[0], stack[0]),
            _ => panic!()
        }
        stack.pop();
        stack.pop();
        gc.collect(&mut stack);
        assert_eq!(num_objects(&gc), 0);
    }
}
<commit_msg>Added AllocPtr which allows for a custom size to be allocated<commit_after>use std::ptr::RawPtr;
use std::mem;
use std::ptr;
use std::rt::heap::{allocate, deallocate};
use std::cell::RefCell;

pub struct Gc<T> {
    gc: RefCell<Gc_<T>>
}
struct Gc_<T> {
    values: Option<AllocPtr>,
    allocated_objects: uint,
    collect_limit: uint
}

struct GcHeader {
    next: Option<AllocPtr>,
    value_size: uint,
    marked: bool,
}

struct AllocPtr {
    ptr: *mut GcHeader
}

impl AllocPtr {
    fn new(value_size: uint) -> AllocPtr {
        unsafe {
            let ptr = allocate(GcHeader::value_offset() + value_size, mem::align_of::<f64>());
            let ptr: *mut GcHeader = mem::transmute(ptr);
            ptr::write(ptr, GcHeader { next: None, value_size: value_size, marked: false });
            AllocPtr { ptr: ptr }
        }
    }
}

#[unsafe_destructor]
impl Drop for AllocPtr {

    fn drop(&mut self) {
        unsafe {
            ptr::read(&*self.ptr);
            let size = GcHeader::value_offset() + self.value_size;
            deallocate(mem::transmute::<*mut GcHeader, *mut u8>(self.ptr), size, mem::align_of::<f64>());
        }
    }
}

impl Deref<GcHeader> for AllocPtr {
    fn deref(&self) -> &GcHeader {
        unsafe { & *self.ptr }
    }
}

impl DerefMut<GcHeader> for AllocPtr {
    fn deref_mut(&mut self) -> &mut GcHeader {
        unsafe { &mut *self.ptr }
    }
}

impl GcHeader {

    fn value(&self) -> *mut () {
        unsafe {
            let ptr: *mut u8 = mem::transmute(self);
            ptr.offset(GcHeader::value_offset() as int) as *mut ()
        }
    }

    fn value_offset() -> uint {
        let hs = mem::size_of::<GcHeader>();
        let max_align = mem::align_of::<f64>();
        hs + ((max_align - (hs % max_align)) % max_align)
    }

    fn total_size<T>() -> uint {
        GcHeader::value_offset() + mem::size_of::<T>()
    }
}

pub struct GcPtr<T> {
    ptr: *mut T
}

impl <T> Deref<T> for GcPtr<T> {
    fn deref(&self) -> &T {
        unsafe { & *self.ptr }
    }
}

impl <T> DerefMut<T> for GcPtr<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

pub trait Traverseable<T> {
    fn traverse(&mut self, func: |&mut T|);
}

impl <T: Traverseable<T>> Gc<T> {

    pub fn new() -> Gc<T> {
        Gc { gc: RefCell::new(Gc_ { values: None, allocated_objects: 0, collect_limit: 100 }) }
    }
    pub fn alloc_and_collect<R: Traverseable<T>>(&self, roots: &mut R, value: T) -> GcPtr<T> {
        let ptr = self.gc.borrow_mut().alloc_and_collect(roots, value);
        GcPtr { ptr: ptr }
    }
    pub fn alloc(&self, value: T) -> GcPtr<T> {
        let ptr = self.gc.borrow_mut().alloc(value);
        GcPtr { ptr: ptr }
    }

    pub fn collect<R: Traverseable<T>>(&self, roots: &mut R) {
        self.gc.borrow_mut().collect(roots);
    }
}
impl <T: Traverseable<T>> Gc_<T> {

    fn alloc_and_collect<R: Traverseable<T>>(&mut self, roots: &mut R, value: T) -> *mut T {
        if self.allocated_objects >= self.collect_limit {
            self.collect(roots);
        }
        self.alloc(value)
    }
    fn alloc(&mut self, value: T) -> *mut T {
        let mut ptr = AllocPtr::new(mem::size_of::<T>());
        ptr.next = self.values.take();
        self.allocated_objects += 1;
        unsafe {
            let p: *mut T = mem::transmute(ptr.value());
            ptr::write(p, value);
            self.values = Some(ptr);
            p
        }
    }

    fn collect<R: Traverseable<T>>(&mut self, roots: &mut R) {
        roots.traverse(|v| self.mark(v));
        self.sweep();
    }

    fn gc_header(value: &mut T) -> &mut GcHeader {
        unsafe {
            let p: *mut u8 = mem::transmute(&mut *value);
            let header = p.offset(-(GcHeader::value_offset() as int));
            mem::transmute(header)
        }
    }

    fn mark(&mut self, value: &mut T) {
        {
            let header = Gc_::gc_header(value);
            if header.marked {
                return
            }
            header.marked = true;
        }
        value.traverse(|child| self.mark(child));
    }

    fn sweep(&mut self) {
        //Usage of unsafe are sadly needed to circumvent the borrow checker
        let mut first = self.values.take();
        {
            let mut maybe_header = &mut first;
            loop {
                let current: &mut Option<AllocPtr> = unsafe { mem::transmute(&*maybe_header) };
                maybe_header = match *maybe_header {
                    Some(ref mut header) => {
                        if !header.marked {
                            let unreached = mem::replace(current, header.next.take());
                            self.free(unreached);
                            continue
                        }
                        else {
                            header.marked = false;
                            let next: &mut Option<AllocPtr> = unsafe { mem::transmute(&mut header.next) };
                            next
                        }
                    }
                    None => break
                };
            }
        }
        self.values = first;
    }
    fn free(&mut self, header: Option<AllocPtr>) {
        self.allocated_objects -= 1;
        drop(header);
    }
}

#[cfg(test)]
mod tests {
    use super::{Gc, Gc_, GcPtr, GcHeader, Traverseable};
    use std::fmt;

    use self::Value::*;

    struct Data_ {
        fields: GcPtr<Vec<Value>>
    }
    impl  Deref<Vec<Value>> for Data_ {
        fn deref(&self) -> &Vec<Value> {
            &*self.fields
        }
    }
    impl  DerefMut<Vec<Value>> for Data_ {
        fn deref_mut(&mut self) -> &mut Vec<Value> {
            &mut *self.fields
        }
    }
    impl  PartialEq for Data_ {
        fn eq(&self, other: &Data_) -> bool {
            self.fields.ptr == other.fields.ptr
        }
    }
    impl  fmt::Show for Data_ {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            self.fields.ptr.fmt(f)
        }
    }

    #[deriving(PartialEq, Show)]
    enum Value {
        Int(int),
        Data(Data_)
    }
    impl  Traverseable<Vec<Value>> for Vec<Value> {
        fn traverse(&mut self, func: |&mut Vec<Value>|) {
            for v in self.iter_mut() {
                match *v {
                    Data(ref mut data) => func(&mut **data),
                    _ => ()
                }
            }
        }
    }
    impl  Traverseable<Vec<Value>> for Value {
        fn traverse(&mut self, func: |&mut Vec<Value>|) {
            match *self {
                Data(ref mut data) => func(&mut **data),
                _ => ()
            }
        }
    }

    fn num_objects<T>(gc: &Gc<T>) -> uint {
        let gc = gc.gc.borrow();
        let mut header: &GcHeader = match gc.values {
            Some(ref x) => &**x,
            None => return 0
        };
        let mut count = 1;
        loop {
            match header.next {
                Some(ref ptr) => {
                    count += 1;
                    header = &**ptr;
                }
                None => break
            }
        }
        count
    }

    fn new_data(p: GcPtr<Vec<Value>>) -> Value {
        Data(Data_ { fields: p })
    }

    #[test]
    fn gc_header() {
        let gc: Gc<Vec<Value>> = Gc::new();
        let mut ptr = gc.alloc(Vec::new());
        let header: *mut _ = &mut *Gc_::gc_header(&mut *ptr);
        let other: *mut _ = &mut **gc.gc.borrow_mut().values.as_mut().unwrap();
        assert_eq!(header, other);
    }

    #[test]
    fn basic() {
        let gc: Gc<Vec<Value>> = Gc::new();
        let mut stack: Vec<Value> = Vec::new();
        stack.push(new_data(gc.alloc(vec![Int(1)])));
        let d2 = new_data(gc.alloc(vec![stack[0]]));
        stack.push(d2);
        assert_eq!(num_objects(&gc), 2);
        gc.collect(&mut stack);
        assert_eq!(num_objects(&gc), 2);
        match stack[0] {
            Data(ref data) => assert_eq!((**data)[0], Int(1)),
            _ => panic!()
        }
        match stack[1] {
            Data(ref data) => assert_eq!((**data)[0], stack[0]),
            _ => panic!()
        }
        stack.pop();
        stack.pop();
        gc.collect(&mut stack);
        assert_eq!(num_objects(&gc), 0);
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate rayon;
fn main() {
    println!("Hello, world!");
}
<commit_msg>Fix 2015 edition tests<commit_after>fn main() {
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>use memory::PAddr;

/// Represents an ELF section header
#[derive(Debug)]
#[repr(C)]
pub struct Header { name_offset: u32
                  , pub ty: Type
                  , pub flags: PAddr
                  , pub address: PAddr
                  , offset: PAddr
                  , pub length: PAddr
                  , link: u32
                  , info: u32
                  , address_align: u32
                  , entry_length: PAddr
                  }

/// Enum representing an ELF file section type.
///
/// Refer to Figure 1-10: "Section Types, sh_type" in Section 1 of the
/// [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
#[repr(u32)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null         = 0
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits = 1
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable = 2
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable  = 3
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela         = 4
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable   = 5
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic     = 6
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes       = 7
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits      = 8
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel         = 9
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib       = 10
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable = 11
    // The remainder is reserved
}

#[derive(Debug)]
#[repr(u32)]
pub enum Flags { Writable    = 0x1
               , Allocated   = 0x2
               , Executable  = 0x4
               }
<commit_msg>[elf] Add OS specific, CPU specific, and User sections<commit_after>use memory::PAddr;
use core::mem;

pub const SHT_LOOS: u32   = 0x60000000;
pub const SHT_HIOS: u32   = 0x6fffffff;
pub const SHT_LOPROC: u32 = 0x70000000;
pub const SHT_HIPROC: u32 = 0x7fffffff;
pub const SHT_LOUSER: u32 = 0x80000000;
pub const SHT_HIUSER: u32 = 0xffffffff;

/// Represents an ELF section header
///
/// Refer to the [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug)]
#[repr(C)]
pub struct Header {
    /// This member specifies the name of the section.
    ///
    /// Its value is an index into the section header string table section,
    /// giving the location of a null-terminated string.
    name_offset: u32
  , /// This member categorizes the section's contents and semantics.
    ty: TypeRepr
  , pub flags: PAddr
  , pub address: PAddr
  , offset: PAddr
  , pub length: PAddr
  , link: u32
  , info: u32
  , address_align: u32
  , entry_length: PAddr
  }

#[derive(Debug, Copy, Clone)]
struct TypeRepr(u32);

impl TypeRepr {
    #[inline] fn as_type(&self) -> Type {
        match self.0 {
            0 => Type::Null
          , 1 => Type::ProgramBits
          , 2 => Type::SymbolTable
          , 3 => Type::StringTable
          , 4 => Type::Rela
          , 5 => Type::HashTable
          , 6 => Type::Dynamic
          , 7 => Type::Notes
          , 8 => Type::NoBits
          , 9 => Type::Rel
          , 10 => Type::Shlib
          , 11 => Type::DynSymTable
          , 14 => Type::InitArray
          , 15 => Type::FiniArray
          , 16 => Type::PreInitArray
          , x @ SHT_LOOS ... SHT_HIOS => Type::OSSpecific(x)
          , x @ SHT_LOPROC ... SHT_HIPROC => Type::ProcessorSpecific(x)
          , x @ SHT_LOUSER ... SHT_HIUSER => Type::User(x)
          , _ => panic!("Invalid section type!")
        }
    }
}

/// Enum representing an ELF file section type.
///
/// Refer to Figure 1-10: "Section Types, sh_type" in Section 1 of the
/// [ELF standard](http://www.sco.com/developers/gabi/latest/ch4.sheader.html)
/// for more information.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Type {
    /// Section type 0: `SHT_NULL`
    ///
    /// This value marks the section header as inactive; it does not have an
    /// associated section. Other members of the section header have
    /// undefined values.
    Null
  , /// Section type 1: `SHT_PROGBITS`
    ///
    /// The section holds information defined by the program, whose format and
    /// meaning are determined solely by the program.
    ProgramBits
  , /// Section type 2: `SHT_SYMTAB`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    SymbolTable
  , /// Section type 3: `SHT_STRTAB`
    ///
    /// The section holds a string table. An object file may have multiple
    /// string table sections.
    StringTable
  , /// Section type 4: `SHT_RELA`
    ///
    /// The section holds relocation entries with explicit addends, such as
    /// type `Elf32_Rela` for the 32-bit class of object files. An object file
    /// may have multiple relocation sections.
    Rela
  , /// Section type 5: `SHT_HASH`
    ///
    /// The section holds a symbol hash table. All objects participating in
    /// dynamic linking must contain a symbol hash table. Currently, an object
    /// file may have only one hash table, but this restriction may be relaxed
    /// in the future.
    HashTable
  , /// Section type 6: `SHT_DYNAMIC`
    ///
    /// The section holds information for dynamic linking. Currently, an object
    /// file may have only one dynamic section, but this restriction may be
    ///  relaxed in the future.
    Dynamic
  , /// Section type 7: `SHT_NOTE`
    ///
    /// The section holds information that marks the file in some way.
    Notes
  , /// Section type 8: `SHT_NOBITS`
    ///
    /// A section of this type occupies no space in the file but otherwise
    /// resembles `SHT_PROGBITS`. Although this section contains no bytes, the
    /// `sh_offset` member contains the conceptual file offset.
    NoBits
  , /// Section type 9: `SHT_REL`
    ///
    /// The section holds relocation entries without explicit addends, such as
    /// type `Elf32_Rel` for the 32-bit class of object files. An object file
    /// may have multiple reloca- tion sections.
    Rel
  , /// Section type 10: `SHT_SHLIB`
    ///
    /// This section type is reserved but has unspecified semantics. Programs
    /// that contain a section of this type do not conform to the ABI.
    Shlib
  , /// Section type 11: `SHT_DYNSYM`
    ///
    /// Typically, `SHT_SYMTAB` provides symbols for link editing, though it
    /// may also be used for dynamic linking. As a complete symbol table, it
    /// may contain many symbols unneces- sary for dynamic linking.
    ///
    /// Consequently, an object file may also contain a `SHT_DYNSYM` section,
    /// which holds a minimal set of dynamic linking symbols, to save space.
    DynSymTable
  , InitArray
  , FiniArray
  , PreInitArray
  , Group
  , SymbolTableShIndex
  , OSSpecific(u32)
  , ProcessorSpecific(u32)
  , User(u32)
}

#[derive(Debug)]
#[repr(u32)]
pub enum Flags { Writable    = 0x1
               , Allocated   = 0x2
               , Executable  = 0x4
               }
<|endoftext|>


<commit_before>const PREFIX_STRING: &'static str = "FIXITY_PREFIX";
const INFIX_STRING: &'static str = "FIXITY_INFIX";
const POSTFIX_STRING: &'static str = "FIXITY_POSTFIX";

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

impl Fixity {
    fn from_string(string: String) -> Option<Self> {
        Some(match string.as_ref() {
            PREFIX_STRING => Fixity::Prefix,
            INFIX_STRING => Fixity::Infix,
            POSTFIX_STRING => Fixity::Postfix,
            _ => return None,
        })
    }
}

impl ToString for Fixity {
    fn to_string(&self) -> String {
        String::from(match *self {
            Fixity::Prefix => PREFIX_STRING,
            Fixity::Infix => INFIX_STRING,
            Fixity::Postfix => POSTFIX_STRING,
        })
    }
}

<commit_msg>Using &str instead of String for fixity<commit_after>const PREFIX_STRING: &'static str = "FIXITY_PREFIX";
const INFIX_STRING: &'static str = "FIXITY_INFIX";
const POSTFIX_STRING: &'static str = "FIXITY_POSTFIX";

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

impl Fixity {
    fn from_str(string: &str) -> Option<Self> {
        Some(match string {
            PREFIX_STRING => Fixity::Prefix,
            INFIX_STRING => Fixity::Infix,
            POSTFIX_STRING => Fixity::Postfix,
            _ => return None,
        })
    }
}

impl ToString for Fixity {
    fn to_string(&self) -> String {
        String::from(match *self {
            Fixity::Prefix => PREFIX_STRING,
            Fixity::Infix => INFIX_STRING,
            Fixity::Postfix => POSTFIX_STRING,
        })
    }
}

<|endoftext|>


<commit_before>//! A utility for writing scripts for use as test executables intended to match the
//! subcommands of Bazel build actions so `rustdoc --test`, which builds and tests
//! code in a single call, can be run as a test target in a hermetic manner.

use std::cmp::Reverse;
use std::collections::{BTreeSet, HashMap};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

#[derive(Debug)]
struct Options {
    /// A list of environment variable keys to parse from the build action env.
    env_keys: BTreeSet<String>,

    /// A list of substrings to strip from [Options::action_argv].
    strip_substrings: Vec<String>,

    /// The path where the script should be written.
    output: PathBuf,

    /// The `argv` of the configured rustdoc build action.
    action_argv: Vec<String>,
}

/// Parse command line arguments
fn parse_args() -> Options {
    let args: Vec<String> = env::args().into_iter().collect();
    let (writer_args, action_args) = {
        let split = args
            .iter()
            .position(|arg| arg == "--")
            .expect("Unable to find split identifier `--`");

        // Converting each set into a vector makes them easier to parse in
        // the absence of nightly features
        let (writer, action) = args.split_at(split);
        (writer.to_vec(), action.to_vec())
    };

    // Remove the leading `--` which is expected to be the first
    // item in `action_args`
    debug_assert_eq!(action_args[0], "--");
    let action_argv = action_args[1..].to_vec();

    let output = writer_args
        .iter()
        .find(|arg| arg.starts_with("--output="))
        .and_then(|arg| arg.splitn(2, '=').last())
        .map(PathBuf::from)
        .expect("Missing `--output` argument");

    let (strip_substring_args, writer_args): (Vec<String>, Vec<String>) = writer_args
        .into_iter()
        .partition(|arg| arg.starts_with("--strip_substring="));

    let mut strip_substrings: Vec<String> = strip_substring_args
        .into_iter()
        .map(|arg| {
            arg.splitn(2, '=')
                .last()
                .expect("--strip_substring arguments must have assignments using `=`")
                .to_owned()
        })
        .collect();

    // Strip substrings should always be in reverse order of the length of each
    // string so when filtering we know that the longer strings are checked
    // first in order to avoid cases where shorter strings might match longer ones.
    strip_substrings.sort_by_key(|b| Reverse(b.len()));
    strip_substrings.dedup();

    let env_keys = writer_args
        .into_iter()
        .filter(|arg| arg.starts_with("--action_env="))
        .map(|arg| {
            arg.splitn(2, '=')
                .last()
                .expect("--env arguments must have assignments using `=`")
                .to_owned()
        })
        .collect();

    Options {
        env_keys,
        strip_substrings,
        output,
        action_argv,
    }
}

/// Write a unix compatible test runner
fn write_test_runner_unix(
    path: &Path,
    env: &HashMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    let mut content = vec![
        "#!/usr/bin/env bash".to_owned(),
        "".to_owned(),
        "exec env - \\".to_owned(),
    ];

    content.extend(env.iter().map(|(key, val)| format!("{}='{}' \\", key, val)));

    let argv_str = argv
        .iter()
        // Remove any substrings found in the argument
        .map(|arg| {
            let mut stripped_arg = arg.to_owned();
            strip_substrings
                .iter()
                .for_each(|substring| stripped_arg = stripped_arg.replace(substring, ""));
            stripped_arg
        })
        .map(|arg| format!("'{}'", arg))
        .collect::<Vec<String>>()
        .join(" ");

    content.extend(vec![argv_str, "".to_owned()]);

    fs::write(path, content.join("\n")).expect("Failed to write test runner");
}

/// Write a windows compatible test runner
fn write_test_runner_windows(
    path: &Path,
    env: &HashMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    let env_str = env
        .iter()
        .map(|(key, val)| format!("$env:{}='{}'", key, val))
        .collect::<Vec<String>>()
        .join(" ; ");

    let argv_str = argv
        .iter()
        // Remove any substrings found in the argument
        .map(|arg| {
            let mut stripped_arg = arg.to_owned();
            strip_substrings
                .iter()
                .for_each(|substring| stripped_arg = stripped_arg.replace(substring, ""));
            stripped_arg
        })
        .map(|arg| format!("'{}'", arg))
        .collect::<Vec<String>>()
        .join(" ");

    let content = vec![
        "@ECHO OFF".to_owned(),
        "".to_owned(),
        format!("powershell.exe -c \"{} ; & {}\"", env_str, argv_str),
        "".to_owned(),
    ];

    fs::write(path, content.join("\n")).expect("Failed to write test runner");
}

#[cfg(target_family = "unix")]
fn set_executable(path: &Path) {
    use std::os::unix::prelude::PermissionsExt;

    let mut perm = fs::metadata(path)
        .expect("Failed to get test runner metadata")
        .permissions();

    perm.set_mode(0o755);
    fs::set_permissions(path, perm).expect("Failed to set permissions on test runner");
}

#[cfg(target_family = "windows")]
fn set_executable(_path: &Path) {
    // Windows determines whether or not a file is executable via the PATHEXT
    // environment variable. This function is a no-op for this platform.
}

fn write_test_runner(
    path: &Path,
    env: &HashMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    if cfg!(target_family = "unix") {
        write_test_runner_unix(path, env, argv, strip_substrings);
    } else if cfg!(target_family = "windows") {
        write_test_runner_windows(path, env, argv, strip_substrings);
    }

    set_executable(path);
}

fn main() {
    let opt = parse_args();

    let env: HashMap<String, String> = env::vars()
        .into_iter()
        .filter(|(key, _)| opt.env_keys.iter().any(|k| k == key))
        .collect();

    write_test_runner(&opt.output, &env, &opt.action_argv, &opt.strip_substrings);
}
<commit_msg>Sort env vars when writing rust_doc_test runners for consistent outputs (#1130)<commit_after>//! A utility for writing scripts for use as test executables intended to match the
//! subcommands of Bazel build actions so `rustdoc --test`, which builds and tests
//! code in a single call, can be run as a test target in a hermetic manner.

use std::cmp::Reverse;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

#[derive(Debug)]
struct Options {
    /// A list of environment variable keys to parse from the build action env.
    env_keys: BTreeSet<String>,

    /// A list of substrings to strip from [Options::action_argv].
    strip_substrings: Vec<String>,

    /// The path where the script should be written.
    output: PathBuf,

    /// The `argv` of the configured rustdoc build action.
    action_argv: Vec<String>,
}

/// Parse command line arguments
fn parse_args() -> Options {
    let args: Vec<String> = env::args().into_iter().collect();
    let (writer_args, action_args) = {
        let split = args
            .iter()
            .position(|arg| arg == "--")
            .expect("Unable to find split identifier `--`");

        // Converting each set into a vector makes them easier to parse in
        // the absence of nightly features
        let (writer, action) = args.split_at(split);
        (writer.to_vec(), action.to_vec())
    };

    // Remove the leading `--` which is expected to be the first
    // item in `action_args`
    debug_assert_eq!(action_args[0], "--");
    let action_argv = action_args[1..].to_vec();

    let output = writer_args
        .iter()
        .find(|arg| arg.starts_with("--output="))
        .and_then(|arg| arg.splitn(2, '=').last())
        .map(PathBuf::from)
        .expect("Missing `--output` argument");

    let (strip_substring_args, writer_args): (Vec<String>, Vec<String>) = writer_args
        .into_iter()
        .partition(|arg| arg.starts_with("--strip_substring="));

    let mut strip_substrings: Vec<String> = strip_substring_args
        .into_iter()
        .map(|arg| {
            arg.splitn(2, '=')
                .last()
                .expect("--strip_substring arguments must have assignments using `=`")
                .to_owned()
        })
        .collect();

    // Strip substrings should always be in reverse order of the length of each
    // string so when filtering we know that the longer strings are checked
    // first in order to avoid cases where shorter strings might match longer ones.
    strip_substrings.sort_by_key(|b| Reverse(b.len()));
    strip_substrings.dedup();

    let env_keys = writer_args
        .into_iter()
        .filter(|arg| arg.starts_with("--action_env="))
        .map(|arg| {
            arg.splitn(2, '=')
                .last()
                .expect("--env arguments must have assignments using `=`")
                .to_owned()
        })
        .collect();

    Options {
        env_keys,
        strip_substrings,
        output,
        action_argv,
    }
}

/// Write a unix compatible test runner
fn write_test_runner_unix(
    path: &Path,
    env: &BTreeMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    let mut content = vec![
        "#!/usr/bin/env bash".to_owned(),
        "".to_owned(),
        "exec env - \\".to_owned(),
    ];

    content.extend(env.iter().map(|(key, val)| format!("{}='{}' \\", key, val)));

    let argv_str = argv
        .iter()
        // Remove any substrings found in the argument
        .map(|arg| {
            let mut stripped_arg = arg.to_owned();
            strip_substrings
                .iter()
                .for_each(|substring| stripped_arg = stripped_arg.replace(substring, ""));
            stripped_arg
        })
        .map(|arg| format!("'{}'", arg))
        .collect::<Vec<String>>()
        .join(" ");

    content.extend(vec![argv_str, "".to_owned()]);

    fs::write(path, content.join("\n")).expect("Failed to write test runner");
}

/// Write a windows compatible test runner
fn write_test_runner_windows(
    path: &Path,
    env: &BTreeMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    let env_str = env
        .iter()
        .map(|(key, val)| format!("$env:{}='{}'", key, val))
        .collect::<Vec<String>>()
        .join(" ; ");

    let argv_str = argv
        .iter()
        // Remove any substrings found in the argument
        .map(|arg| {
            let mut stripped_arg = arg.to_owned();
            strip_substrings
                .iter()
                .for_each(|substring| stripped_arg = stripped_arg.replace(substring, ""));
            stripped_arg
        })
        .map(|arg| format!("'{}'", arg))
        .collect::<Vec<String>>()
        .join(" ");

    let content = vec![
        "@ECHO OFF".to_owned(),
        "".to_owned(),
        format!("powershell.exe -c \"{} ; & {}\"", env_str, argv_str),
        "".to_owned(),
    ];

    fs::write(path, content.join("\n")).expect("Failed to write test runner");
}

#[cfg(target_family = "unix")]
fn set_executable(path: &Path) {
    use std::os::unix::prelude::PermissionsExt;

    let mut perm = fs::metadata(path)
        .expect("Failed to get test runner metadata")
        .permissions();

    perm.set_mode(0o755);
    fs::set_permissions(path, perm).expect("Failed to set permissions on test runner");
}

#[cfg(target_family = "windows")]
fn set_executable(_path: &Path) {
    // Windows determines whether or not a file is executable via the PATHEXT
    // environment variable. This function is a no-op for this platform.
}

fn write_test_runner(
    path: &Path,
    env: &BTreeMap<String, String>,
    argv: &[String],
    strip_substrings: &[String],
) {
    if cfg!(target_family = "unix") {
        write_test_runner_unix(path, env, argv, strip_substrings);
    } else if cfg!(target_family = "windows") {
        write_test_runner_windows(path, env, argv, strip_substrings);
    }

    set_executable(path);
}

fn main() {
    let opt = parse_args();

    let env: BTreeMap<String, String> = env::vars()
        .into_iter()
        .filter(|(key, _)| opt.env_keys.iter().any(|k| k == key))
        .collect();

    write_test_runner(&opt.output, &env, &opt.action_argv, &opt.strip_substrings);
}
<|endoftext|>


<commit_before>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  pub header: Header,
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  Independent = 0,
  LeftSide    = 1,
  RightSide   = 2,
  MiddleSide  = 3,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  Frame(u32),
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  pub block_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub channel_assignment: ChannelAssignment,
  pub bits_per_sample: usize,
  pub number: NumberType,
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<commit_msg>Remove explicit numbers in ChannelAssignment enum<commit_after>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  pub header: Header,
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  Independent,
  LeftSide,
  RightSide,
  MiddleSide,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  Frame(u32),
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  pub block_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub channel_assignment: ChannelAssignment,
  pub bits_per_sample: usize,
  pub number: NumberType,
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<|endoftext|>


<commit_before>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
                  .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
                  .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    (RESOLUTION_X as f32, RESOLUTION_Y as f32)
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{CloseRequested, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D, R};
    use gfx_app::controls::Control;
    use character::controls::CharacterControl;

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => WindowStatus::Close,
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom(Control::Negative);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom(Control::Plus);
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom(Control::Released);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character(CharacterControl::Up);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character(CharacterControl::Down);
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.move_character(CharacterControl::YMoveStop);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character(CharacterControl::Left);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character(CharacterControl::Right);
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.move_character(CharacterControl::XMoveStop);
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
              controls.reload_weapon(true);
              WindowStatus::Open
            },
            KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
              controls.reload_weapon(false);
              WindowStatus::Open
            },
            KeyboardInput { state: Pressed, modifiers, .. } => {
              if modifiers.ctrl {
                controls.ctrl_pressed(true);
              }
              WindowStatus::Open
            }
            KeyboardInput { state: Released, modifiers, .. } => {
              if !modifiers.ctrl {
                controls.ctrl_pressed(false);
              }
              WindowStatus::Open
            }
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

<commit_msg>Refactor even more controls<commit_after>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D, R};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
                  .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
                  .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
  fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    (RESOLUTION_X as f32, RESOLUTION_Y as f32)
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => {Self::process_keyboard_input(input, controls)},
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }

  fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
    match input {
      KeyboardInput { virtual_keycode: Some(Escape), .. } => WindowStatus::Close,
      KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
        controls.zoom(Control::Negative);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
        controls.zoom(Control::Plus);
        WindowStatus::Open
      }
      KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
      KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
        controls.zoom(Control::Released);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
        controls.move_character(CharacterControl::Up);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
        controls.move_character(CharacterControl::Down);
        WindowStatus::Open
      }
      KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
      KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
        controls.move_character(CharacterControl::YMoveStop);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
        controls.move_character(CharacterControl::Left);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
        controls.move_character(CharacterControl::Right);
        WindowStatus::Open
      }
      KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
      KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
        controls.move_character(CharacterControl::XMoveStop);
        WindowStatus::Open
      }
      KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
        controls.reload_weapon(true);
        WindowStatus::Open
      },
      KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
        controls.reload_weapon(false);
        WindowStatus::Open
      },
      KeyboardInput { state: Pressed, modifiers, .. } => {
        if modifiers.ctrl {
          controls.ctrl_pressed(true);
        }
        WindowStatus::Open
      }
      KeyboardInput { state: Released, modifiers, .. } => {
        if !modifiers.ctrl {
          controls.ctrl_pressed(false);
        }
        WindowStatus::Open
      }
    }
  }
}

<|endoftext|>


<commit_before>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Zombie shooter");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat,
      DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn poll_events(&mut self) -> Option<GameStatus>;

  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);

  fn get_viewport_size(&mut self) -> (u32, u32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (u32, u32) {
    self.window
        .get_inner_size()
        .unwrap_or((RESOLUTION_X, RESOLUTION_Y))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> Option<GameStatus> {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, Closed, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status: Option<GameStatus> = None;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => Some(GameStatus::Quit),
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              controls.move_map_left();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              None
            }
            _ => None,
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            None
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            None
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            None
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            None
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            None
          }
          Closed => Some(GameStatus::Quit),
          Resized(_, _) => {
            gfx_window_glutin::update_views(w, m_rtv, m_dsv);
            Some(GameStatus::Quit)
          }
          _ => None,
        }
      } else {
        None
      };
    });
    game_status
  }
}

<commit_msg>Update function introduction order in Window trait<commit_after>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Zombie shooter");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat,
      DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum GameStatus {
  Quit,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (u32, u32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> Option<GameStatus>;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (u32, u32) {
    self.window
        .get_inner_size()
        .unwrap_or((RESOLUTION_X, RESOLUTION_Y))
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> Option<GameStatus> {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, Closed, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let w = &self.window;
    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status: Option<GameStatus> = None;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => Some(GameStatus::Quit),
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              controls.move_map_left();
              None
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              None
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              None
            }
            _ => None,
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            None
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            None
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            None
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            None
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            None
          }
          Closed => Some(GameStatus::Quit),
          Resized(_, _) => {
            gfx_window_glutin::update_views(w, m_rtv, m_dsv);
            Some(GameStatus::Quit)
          }
          _ => None,
        }
      } else {
        None
      };
    });
    game_status
  }
}

<|endoftext|>


<commit_before>extern crate libc;

pub mod anoncreds;
pub mod crypto;
pub mod sovrin;
pub mod wallet;

use std::collections::HashMap;
use std::mem;
use std::sync::{Arc, Mutex, Once, ONCE_INIT};

use self::libc::{c_char, c_uchar};
use super::SovrinClient;

#[derive(Clone)]
pub struct SingletonClients {
    inner: Arc<Mutex<(HashMap<i32, SovrinClient>, i32)>>
}

pub fn get_active_clients() -> SingletonClients {
    static mut SINGLETON: *const SingletonClients = 0 as *const SingletonClients;
    static ONCE: Once = ONCE_INIT;

    unsafe {
        ONCE.call_once(|| {
            let singleton = SingletonClients {
                inner: Arc::new(Mutex::new((HashMap::new(), 1)))
            };
            SINGLETON = mem::transmute(Box::new(singleton));
        });
        (*SINGLETON).clone()
    }
}

#[no_mangle]
pub extern fn init_client(host_and_port: *const c_char) -> i32 {
    unimplemented!();
}

#[no_mangle]
pub extern fn release_client(client_id: i32) -> i32 {
    unimplemented!();
}

#[no_mangle]
pub extern fn free_str(c_ptr: *mut c_char) {
    unimplemented!();
}<commit_msg>Initial implementation for init/release client in C API.<commit_after>extern crate libc;

pub mod anoncreds;
pub mod crypto;
pub mod sovrin;
pub mod wallet;

use std::collections::HashMap;
use std::mem;
use std::sync::{Arc, Mutex, Once, ONCE_INIT};

use self::libc::{c_char, c_uchar};
use super::SovrinClient;

#[derive(Clone)]
pub struct SingletonClients {
    inner: Arc<Mutex<(HashMap<i32, SovrinClient>, i32)>>
}

pub fn get_active_clients() -> SingletonClients {
    static mut SINGLETON: *const SingletonClients = 0 as *const SingletonClients;
    static ONCE: Once = ONCE_INIT;

    unsafe {
        ONCE.call_once(|| {
            let singleton = SingletonClients {
                inner: Arc::new(Mutex::new((HashMap::new(), 1)))
            };
            SINGLETON = mem::transmute(Box::new(singleton));
        });
        (*SINGLETON).clone()
    }
}

#[no_mangle]
pub extern fn init_client(host_and_port: *const c_char) -> i32 {
    let s = get_active_clients();
    let (ref mut clients, mut cl_id): (HashMap<i32, SovrinClient>, i32) = *s.inner.lock().unwrap();

    while clients.contains_key(&cl_id) {
        cl_id += 1;
        if cl_id < 0 {
            cl_id = 1;
        }
    }

    clients.insert(cl_id, SovrinClient::new());

    cl_id
}

#[no_mangle]
pub extern fn release_client(client_id: i32) -> i32 {
    let s = get_active_clients();
    let ref mut clients: HashMap<i32, SovrinClient> = (*s.inner.lock().unwrap()).0;

    if clients.contains_key(&client_id) {
        clients.remove(&client_id);
        0
    } else {
        -1
    }
}

#[no_mangle]
pub extern fn free_str(c_ptr: *mut c_char) {
    unimplemented!();
}<|endoftext|>