<commit_before>use util::io_err;
use std::io::{Write, Read, ErrorKind};
use std::io::Result as IoResult;
use std::net::{IpAddr, TcpStream};
use std::mem;

enum AuthMethod<'s> {
    NoAuth,
    UPass(&'s str, &'s str)
}

pub trait ReadU8 {
    fn read_u8(&mut self) -> IoResult<u8>;
}

impl ReadU8 for TcpStream {
    #[inline]
    fn read_u8(&mut self) -> IoResult<u8> {
        let mut buf = [0u8];
        try!(self.read_exact(&mut buf));
        Ok(buf[0])
    }
}

//pub trait WriteU8 {
//    fn read_u8(&mut self) -> IoResult<u8>;
//}
//
//impl ReadU8 for TcpStream {
//    #[inline]
//    fn read_u8(&mut self) -> IoResult<u8> {
//        let mut buf = [0u8];
//        try!(self.read_exact(&mut buf));
//        Ok(buf[0])
//    }
//}

pub trait Socks5Destination {
    fn write_destination(&self, &mut TcpStream) -> IoResult<()>;
}

impl<'a> Socks5Destination for &'a str {
    fn write_destination(&self, stream: &mut TcpStream) -> IoResult<()> {
        if self.len() > 255 {
            return io_err(ErrorKind::Other, "Domain length is too long");
        }

        try!(stream.write(&[0x03, self.len() as u8]));
        try!(stream.write(&self.as_bytes()));
        Ok(())
    }
}

impl<'a> Socks5Destination for IpAddr {
    fn write_destination(&self, stream: &mut TcpStream) -> IoResult<()> {
        match *self {
            //IpAddr::V4(a, b, c, d) => try!(stream.write_all(&[0x01, a, b, c, d])),
            IpAddr::V4(addr) => {
                try!(stream.write_all(&[0x01]));
                try!(stream.write_all(&addr.octets()));
            },
            IpAddr::V6(addr) => {
                let segments = addr.segments();
                try!(stream.write_all(&[0x04]));
                for &pair in segments.iter() {
                    let array : [u8; 2] = unsafe {
                        mem::transmute(pair.to_be())
                    };
                    try!(stream.write_all(&array));
                }
            }
        }

        Ok(())
    }
}

pub struct Socks5<'a> {
    socks_host: &'a str,
    socks_port: u16,
    socks_auth: AuthMethod<'a>,
}

impl<'a> Socks5<'a> {
    pub fn new(host: &'a str, port: u16) -> Socks5 {
        Socks5 {
            socks_host: host,
            socks_port: port,
            socks_auth: AuthMethod::NoAuth
        }
    }

    pub fn login(&mut self, uname: &'a str, passwd: &'a str) {
        self.socks_auth = AuthMethod::UPass(uname, passwd);
    }

    pub fn connect<T: Socks5Destination>(&mut self, destination: T, port: u16)
                                                        -> IoResult<TcpStream> {
        let mut stream = try!(TcpStream::connect((self.socks_host, self.socks_port)));
        try!(stream.write(&[0x05u8]));
        match self.socks_auth {
            AuthMethod::NoAuth => { try!(stream.write(&[0x01u8, 0x00])); },
            AuthMethod::UPass(..) => { try!(stream.write(&[0x01u8, 0x02])); }
        }

        if try!(stream.read_u8()) != 0x05 {
            return io_err(ErrorKind::Other, "Unexpected SOCKS version number");
        }

        match try!(stream.read_u8()) {
            0x00 => {
                match self.socks_auth {
                    AuthMethod::NoAuth => { /* Continue */ },
                    _ => return io_err(ErrorKind::Other,
                        "Wrong authentication method from server")
                }
            }
            0x02 => {
                match self.socks_auth {
                    AuthMethod::UPass(uname, passwd) => {
                        try!(stream.write_all(&[0x01u8, uname.len() as u8]));
                        //try!(stream.write_str(uname));
                        try!(write!(stream, "{}", uname));
                        try!(stream.write_all(&[passwd.len() as u8]));
                        try!(write!(stream, "{}", passwd));
                        //try!(stream.write_str(passwd));

                        if try!(stream.read_u8()) != 0x01 {
                            return io_err(ErrorKind::Other,
                                "Invalid authentication version");
                        }

                        if try!(stream.read_u8()) != 0x00 {
                            return io_err(ErrorKind::ConnectionRefused, "Authentication failed");
                        }
                    }
                    _ => { return io_err(ErrorKind::Other,
                            "Wrong authentication method from server");
                    }
                }
            }
            0xFF => { return io_err(ErrorKind::ConnectionRefused,
                      "Server refused authentication methods"); }
            _ => { return io_err(ErrorKind::Other,
                    "Wrong authentication method from server"); }
        }

        try!(stream.write(&[0x05u8, 0x01, 0x00]));
        try!(destination.write_destination(&mut stream));
        let be_port = port.to_be();
        let array : [u8; 2] = unsafe { mem::transmute(be_port) };
        try!(stream.write_all(&array));

        if try!(stream.read_u8()) != 0x05 {
            return io_err(ErrorKind::Other, "Invalid SOCKS version number");
        }

        match try!(stream.read_u8()) {
            0x00 => {
                let _null = try!(stream.read_u8());

                match try!(stream.read_u8()) {
                    0x01 => {
                        let mut _ipv4 = [0; 4];
                        try!(stream.read_exact(&mut _ipv4));
                    }
                    0x03 => {
                        let addrlen = try!(stream.read_u8());
                        let mut _domain = Vec::with_capacity(addrlen as usize);
                        try!(stream.read_exact(&mut _domain));
                    }
                    0x04 => {
                        let mut _ipv6 = [0; 16];
                        try!(stream.read_exact(&mut _ipv6));
                    }
                    _ => return io_err(ErrorKind::Other, "Invalid address type"),
                }

                let mut _port_slice : [u8; 2] = [0u8; 2];
                try!(stream.read_exact(&mut _port_slice));
                let _port_be : u16 = unsafe { mem::transmute(_port_slice) };
                let _port = u16::from_be(_port_be);
                Ok(stream)
            }
            0x01 => io_err(ErrorKind::Other, "General failure"),
            0x02 => io_err(ErrorKind::Other, "Connection not allowed by ruleset"),
            0x03 => io_err(ErrorKind::NotConnected, "Network unreachable"),
            0x04 => io_err(ErrorKind::Other, "Host unreachable"),
            0x05 => io_err(ErrorKind::ConnectionRefused, "Connection refused by destination"),
            0x06 => io_err(ErrorKind::Other, "TTL expired"),
            0x07 => io_err(ErrorKind::Other, "Protocol Error"),
            0x08 => io_err(ErrorKind::Other, "Address type not supported"),
            _ => io_err(ErrorKind::Other, "Unknown error")
        }
    }
}
<commit_msg>remove commented-out code, sorry...<commit_after>use util::io_err;
use std::io::{Write, Read, ErrorKind};
use std::io::Result as IoResult;
use std::net::{IpAddr, TcpStream};
use std::mem;

enum AuthMethod<'s> {
    NoAuth,
    UPass(&'s str, &'s str)
}

pub trait ReadU8 {
    fn read_u8(&mut self) -> IoResult<u8>;
}

impl ReadU8 for TcpStream {
    #[inline]
    fn read_u8(&mut self) -> IoResult<u8> {
        let mut buf = [0u8];
        try!(self.read_exact(&mut buf));
        Ok(buf[0])
    }
}

pub trait Socks5Destination {
    fn write_destination(&self, &mut TcpStream) -> IoResult<()>;
}

impl<'a> Socks5Destination for &'a str {
    fn write_destination(&self, stream: &mut TcpStream) -> IoResult<()> {
        if self.len() > 255 {
            return io_err(ErrorKind::Other, "Domain length is too long");
        }

        try!(stream.write(&[0x03, self.len() as u8]));
        try!(stream.write(&self.as_bytes()));
        Ok(())
    }
}

impl<'a> Socks5Destination for IpAddr {
    fn write_destination(&self, stream: &mut TcpStream) -> IoResult<()> {
        match *self {
            IpAddr::V4(addr) => {
                try!(stream.write_all(&[0x01]));
                try!(stream.write_all(&addr.octets()));
            },
            IpAddr::V6(addr) => {
                let segments = addr.segments();
                try!(stream.write_all(&[0x04]));
                for &pair in segments.iter() {
                    let array : [u8; 2] = unsafe {
                        mem::transmute(pair.to_be())
                    };
                    try!(stream.write_all(&array));
                }
            }
        }

        Ok(())
    }
}

pub struct Socks5<'a> {
    socks_host: &'a str,
    socks_port: u16,
    socks_auth: AuthMethod<'a>,
}

impl<'a> Socks5<'a> {
    pub fn new(host: &'a str, port: u16) -> Socks5 {
        Socks5 {
            socks_host: host,
            socks_port: port,
            socks_auth: AuthMethod::NoAuth
        }
    }

    pub fn login(&mut self, uname: &'a str, passwd: &'a str) {
        self.socks_auth = AuthMethod::UPass(uname, passwd);
    }

    pub fn connect<T: Socks5Destination>(&mut self, destination: T, port: u16)
                                                        -> IoResult<TcpStream> {
        let mut stream = try!(TcpStream::connect((self.socks_host, self.socks_port)));
        try!(stream.write(&[0x05u8]));
        match self.socks_auth {
            AuthMethod::NoAuth => { try!(stream.write(&[0x01u8, 0x00])); },
            AuthMethod::UPass(..) => { try!(stream.write(&[0x01u8, 0x02])); }
        }

        if try!(stream.read_u8()) != 0x05 {
            return io_err(ErrorKind::Other, "Unexpected SOCKS version number");
        }

        match try!(stream.read_u8()) {
            0x00 => {
                match self.socks_auth {
                    AuthMethod::NoAuth => { /* Continue */ },
                    _ => return io_err(ErrorKind::Other,
                        "Wrong authentication method from server")
                }
            }
            0x02 => {
                match self.socks_auth {
                    AuthMethod::UPass(uname, passwd) => {
                        try!(stream.write_all(&[0x01u8, uname.len() as u8]));
                        //try!(stream.write_str(uname));
                        try!(write!(stream, "{}", uname));
                        try!(stream.write_all(&[passwd.len() as u8]));
                        try!(write!(stream, "{}", passwd));
                        //try!(stream.write_str(passwd));

                        if try!(stream.read_u8()) != 0x01 {
                            return io_err(ErrorKind::Other,
                                "Invalid authentication version");
                        }

                        if try!(stream.read_u8()) != 0x00 {
                            return io_err(ErrorKind::ConnectionRefused, "Authentication failed");
                        }
                    }
                    _ => { return io_err(ErrorKind::Other,
                            "Wrong authentication method from server");
                    }
                }
            }
            0xFF => { return io_err(ErrorKind::ConnectionRefused,
                      "Server refused authentication methods"); }
            _ => { return io_err(ErrorKind::Other,
                    "Wrong authentication method from server"); }
        }

        try!(stream.write(&[0x05u8, 0x01, 0x00]));
        try!(destination.write_destination(&mut stream));
        let be_port = port.to_be();
        let array : [u8; 2] = unsafe { mem::transmute(be_port) };
        try!(stream.write_all(&array));

        if try!(stream.read_u8()) != 0x05 {
            return io_err(ErrorKind::Other, "Invalid SOCKS version number");
        }

        match try!(stream.read_u8()) {
            0x00 => {
                let _null = try!(stream.read_u8());

                match try!(stream.read_u8()) {
                    0x01 => {
                        let mut _ipv4 = [0; 4];
                        try!(stream.read_exact(&mut _ipv4));
                    }
                    0x03 => {
                        let addrlen = try!(stream.read_u8());
                        let mut _domain = Vec::with_capacity(addrlen as usize);
                        try!(stream.read_exact(&mut _domain));
                    }
                    0x04 => {
                        let mut _ipv6 = [0; 16];
                        try!(stream.read_exact(&mut _ipv6));
                    }
                    _ => return io_err(ErrorKind::Other, "Invalid address type"),
                }

                let mut _port_slice : [u8; 2] = [0u8; 2];
                try!(stream.read_exact(&mut _port_slice));
                let _port_be : u16 = unsafe { mem::transmute(_port_slice) };
                let _port = u16::from_be(_port_be);
                Ok(stream)
            }
            0x01 => io_err(ErrorKind::Other, "General failure"),
            0x02 => io_err(ErrorKind::Other, "Connection not allowed by ruleset"),
            0x03 => io_err(ErrorKind::NotConnected, "Network unreachable"),
            0x04 => io_err(ErrorKind::Other, "Host unreachable"),
            0x05 => io_err(ErrorKind::ConnectionRefused, "Connection refused by destination"),
            0x06 => io_err(ErrorKind::Other, "TTL expired"),
            0x07 => io_err(ErrorKind::Other, "Protocol Error"),
            0x08 => io_err(ErrorKind::Other, "Address type not supported"),
            _ => io_err(ErrorKind::Other, "Unknown error")
        }
    }
}
<|endoftext|>


<commit_before>//! Documentation of TinyTemplate's template syntax.
//!
//! ### Context Types
//!
//! TinyTemplate uses `serde_json`'s Value structure to represent the context. Therefore, any
//! `Serializable` structure can be used as a context. All values in such structures are mapped to
//! their JSON representations - booleans, numbers, strings, arrays, objects and nulls.
//!
//! ### Values
//!
//! Template values are marked with `{...}`. For example, this will look up the "name" field in
//! the context structure and insert it into the rendered string:
//!
//! ```text
//! Hello, {name}, how are you?
//! ```
//!
//! Optionally, a value formatter may be provided. The value formatter must have been registered
//! with the [`TinyTemplate.add_formatter`](../struct.TinyTemplate.html#method.add_formatter)
//! function prior to rendering or an error will be generated. This will call the formatter function
//! registered as "percent_formatter" with the value of the "percentage" field:
//!
//! ```text
//! Give it {percentage | percent_formatter}!
//! ```
//!
//! The value may be a dotted path through a hierarchy of context objects. This will look up the
//! "friend" field in the context structure, then substitute the "name" field from the "friend"
//! object.
//!
//! ```text
//! And hello to {friend.name} as well!
//! ```
//!
//! Additionally, you may use the `@root` keyword to refer to the root object of your context.
//! Since TinyTemplate can't normally print complex context objects, this is only useful if the
//! context is a simple object like an integer or string.
//!
//! ### Conditionals
//!
//! TinyTemplate blocks are marked with `{{...}}` - double-braces where values are single-braces.
//!
//! Conditionals are denoted by "{{ if path }}...{{ else }}...{{ endif }}". The Else block is
//! optional. Else-if is not currently supported. If "path" evaluates to a truthy expression
//! (true if boolean, non-zero if numeric, non-empty for strings and arrays, and non-null for
//! objects) then the section of the template between "if" and "else" is evaluated, otherwise the
//! section between "else" and "endif" (if present) is evaluated.
//!
//! ```text
//! {{ if user.is_birthday }}
//! Happy Birthday!
//! {{ else }}
//! Have a nice day!
//! {{ endif }}
//! ```
//!
//! The condition can be negated by using "{{ if not path }}":
//!
//! ```text
//! {{ if not user.is_birthday }}
//! Have a nice day!
//! {{ else }}
//! Happy Birthday!
//! {{ endif }}
//! ```
//!
//! If desired, the `@root` keyword can be used to branch on the root context object.
//!
//! ### Loops
//!
//! TinyTemplate supports iterating over the values of arrays. Only arrays are supported. Loops
//! are denoted by "{{ for value_name in value.path }}...{{ endfor }}". The section of the template between
//! the two tags will be executed once for each value in the array denoted by "value.path".
//!
//! ```text
//! Hello to {{ for name in guests }}
//! {name}
//! {{ endfor }}
//! ```
//!
//! If the iteration value chosen in the "for" tag is the same as that of a regular context value,
//! the name in the tag will shadow the context value for the scope of the loop. For nested loops,
//! inner loops will shadow the values of outer loops.
//!
//! ```text
//! {{ for person in guests }}
//! Hello to {person}{{ for person in person.friends }} and your friend {person}{{ endfor }}
//! {{ endfor }}
//! ```
//!
//! There are three special values which are available within a loop:
//!
//! * `@index` - zero-based index of the current value within the array.
//! * `@first` - true if this is the first iteration of the loop, otherwise false.
//! * `@last` - true if this is the last iteration of the loop, otherwise false.
//!
//! ```text
//! Hello to {{ for name in guests -}}
//! { @index }. {name},
//! {{- endfor }}
//! ```
//!
//!
//! In case of nested loops, these values refer to the innermost loop which contains them.
//!
//! If the root context object is a list, the `@root` keyword can be used to iterate over the
//! root object.
//!
//! ### With Blocks
//!
//! Templates can use with blocks to partially shadows the outer context, the same way that
//! for-loops do. These are formed like so:
//!
//! "{{ with path.to.value as name }}..{{ endwith }}""
//!
//! For example:
//!
//! ```text
//! {{ with person.spouse as s }}
//! Hello { s.name }!
//! {{ endwith }}
//! ```
//!
//! This looks up "person.spouse" and adds that to the context as "s" within the block. Only the
//! name "s" is shadowed within the with block and otherwise the outer context is still accessible.
//!
//! ### Trimming Whitespace
//!
//! If a block tag, comment or value tag includes a "-" character at the start, the trailing
//! whitespace of the previous text section will be skipped in the output. Likewise, if the tag
//! ends with a "-", the leading whitespace of the following text will be skipped.
//!
//! ```text
//! Hello { friend.name -}
//! , how are you?
//!
//! {{- if status.good }} I am fine.               {{- endif }}
//! ```
//!
//! This will print "Hello friend, how are you? I am fine." without the newlines or extra spaces.
//!
//! ### Calling other Templates
//!
//! Templates may call other templates by name. The other template must have been registered using
//! the [`TinyTemplate.add_template`](../struct.TinyTemplate.html#method.add_template) function
//! before rendering or an error will be generated. This is done with the "call" tag:
//!
//! "{{ call template_name with path.to.context }}"
//!
//! The call tag has no closing tag. This will look up the "path.to.context" path in the current
//! context, then render the "template_name" template using the value at that path as the context
//! for the other template. The string produced by the called template is then inserted into the
//! output from the calling template. This can be used for a limited form of template code reuse.
//!
//! ### Comments
//!
//! Comments in the templates are denoted by "{# comment text #}". Comments will be skipped when
//! rendering the template, though whitespace adjacent to comments will not be stripped unless the
//! "-" is added. For example:
//!
//! ```text
//! Hello
//!
//! {#- This is a comment #} world!
//! ```
//!
//! This will print "Hello world!".
//!
//! ### Escaping Curly Braces
//!
//! If your template contains opening curly-braces (`{`), they must be escaped using a leading `\`
//! character. For example:
//!
//! ```text
//! h2 \{
//!     font-size: {fontsize};
//! }
//! ```
//!
//! If using a string literal in rust source code, the `\` itself must be escaped, producing `\\{`.
//!

// There's nothing here, this module is solely for documentation.
<commit_msg>Adjust wording.<commit_after>//! Documentation of TinyTemplate's template syntax.
//!
//! ### Context Types
//!
//! TinyTemplate uses `serde_json`'s Value structure to represent the context. Therefore, any
//! `Serializable` structure can be used as a context. All values in such structures are mapped to
//! their JSON representations - booleans, numbers, strings, arrays, objects and nulls.
//!
//! ### Values
//!
//! Template values are marked with `{...}`. For example, this will look up the "name" field in
//! the context structure and insert it into the rendered string:
//!
//! ```text
//! Hello, {name}, how are you?
//! ```
//!
//! Optionally, a value formatter may be provided. The value formatter must have been registered
//! with the [`TinyTemplate.add_formatter`](../struct.TinyTemplate.html#method.add_formatter)
//! function prior to rendering or an error will be generated. This will call the formatter function
//! registered as "percent_formatter" with the value of the "percentage" field:
//!
//! ```text
//! Give it {percentage | percent_formatter}!
//! ```
//!
//! The value may be a dotted path through a hierarchy of context objects. This will look up the
//! "friend" field in the context structure, then substitute the "name" field from the "friend"
//! object.
//!
//! ```text
//! And hello to {friend.name} as well!
//! ```
//!
//! Additionally, you may use the `@root` keyword to refer to the root object of your context.
//! Since TinyTemplate can't normally print complex context objects, this is only useful if the
//! context is a simple object like an integer or string.
//!
//! ### Conditionals
//!
//! TinyTemplate blocks are marked with `{{...}}` - double-braces where values are single-braces.
//!
//! Conditionals are denoted by "{{ if path }}...{{ else }}...{{ endif }}". The Else block is
//! optional. Else-if is not currently supported. If "path" evaluates to a truthy expression
//! (true if boolean, non-zero if numeric, non-empty for strings and arrays, and non-null for
//! objects) then the section of the template between "if" and "else" is evaluated, otherwise the
//! section between "else" and "endif" (if present) is evaluated.
//!
//! ```text
//! {{ if user.is_birthday }}
//! Happy Birthday!
//! {{ else }}
//! Have a nice day!
//! {{ endif }}
//! ```
//!
//! The condition can be negated by using "{{ if not path }}":
//!
//! ```text
//! {{ if not user.is_birthday }}
//! Have a nice day!
//! {{ else }}
//! Happy Birthday!
//! {{ endif }}
//! ```
//!
//! If desired, the `@root` keyword can be used to branch on the root context object.
//!
//! ### Loops
//!
//! TinyTemplate supports iterating over the values of arrays. Only arrays are supported. Loops
//! are denoted by "{{ for value_name in value.path }}...{{ endfor }}". The section of the template between
//! the two tags will be executed once for each value in the array denoted by "value.path".
//!
//! ```text
//! Hello to {{ for name in guests }}
//! {name}
//! {{ endfor }}
//! ```
//!
//! If the iteration value chosen in the "for" tag is the same as that of a regular context value,
//! the name in the tag will shadow the context value for the scope of the loop. For nested loops,
//! inner loops will shadow the values of outer loops.
//!
//! ```text
//! {{ for person in guests }}
//! Hello to {person}{{ for person in person.friends }} and your friend {person}{{ endfor }}
//! {{ endfor }}
//! ```
//!
//! There are three special values which are available within a loop:
//!
//! * `@index` - zero-based index of the current value within the array.
//! * `@first` - true if this is the first iteration of the loop, otherwise false.
//! * `@last` - true if this is the last iteration of the loop, otherwise false.
//!
//! ```text
//! Hello to {{ for name in guests -}}
//! { @index }. {name},
//! {{- endfor }}
//! ```
//!
//!
//! In case of nested loops, these values refer to the innermost loop which contains them.
//!
//! If the root context object is an array, the `@root` keyword can be used to iterate over the
//! root object.
//!
//! ### With Blocks
//!
//! Templates can use with blocks to partially shadows the outer context, the same way that
//! for-loops do. These are formed like so:
//!
//! "{{ with path.to.value as name }}..{{ endwith }}""
//!
//! For example:
//!
//! ```text
//! {{ with person.spouse as s }}
//! Hello { s.name }!
//! {{ endwith }}
//! ```
//!
//! This looks up "person.spouse" and adds that to the context as "s" within the block. Only the
//! name "s" is shadowed within the with block and otherwise the outer context is still accessible.
//!
//! ### Trimming Whitespace
//!
//! If a block tag, comment or value tag includes a "-" character at the start, the trailing
//! whitespace of the previous text section will be skipped in the output. Likewise, if the tag
//! ends with a "-", the leading whitespace of the following text will be skipped.
//!
//! ```text
//! Hello { friend.name -}
//! , how are you?
//!
//! {{- if status.good }} I am fine.               {{- endif }}
//! ```
//!
//! This will print "Hello friend, how are you? I am fine." without the newlines or extra spaces.
//!
//! ### Calling other Templates
//!
//! Templates may call other templates by name. The other template must have been registered using
//! the [`TinyTemplate.add_template`](../struct.TinyTemplate.html#method.add_template) function
//! before rendering or an error will be generated. This is done with the "call" tag:
//!
//! "{{ call template_name with path.to.context }}"
//!
//! The call tag has no closing tag. This will look up the "path.to.context" path in the current
//! context, then render the "template_name" template using the value at that path as the context
//! for the other template. The string produced by the called template is then inserted into the
//! output from the calling template. This can be used for a limited form of template code reuse.
//!
//! ### Comments
//!
//! Comments in the templates are denoted by "{# comment text #}". Comments will be skipped when
//! rendering the template, though whitespace adjacent to comments will not be stripped unless the
//! "-" is added. For example:
//!
//! ```text
//! Hello
//!
//! {#- This is a comment #} world!
//! ```
//!
//! This will print "Hello world!".
//!
//! ### Escaping Curly Braces
//!
//! If your template contains opening curly-braces (`{`), they must be escaped using a leading `\`
//! character. For example:
//!
//! ```text
//! h2 \{
//!     font-size: {fontsize};
//! }
//! ```
//!
//! If using a string literal in rust source code, the `\` itself must be escaped, producing `\\{`.
//!

// There's nothing here, this module is solely for documentation.
<|endoftext|>


<commit_before>// 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.

use std::fmt;
use super::attachinfo::SBAttachInfo;
use super::breakpoint::SBBreakpoint;
use super::broadcaster::SBBroadcaster;
use super::debugger::SBDebugger;
use super::error::SBError;
use super::filespec::SBFileSpec;
use super::launchinfo::SBLaunchInfo;
use super::module::SBModule;
use super::modulespec::SBModuleSpec;
use super::platform::SBPlatform;
use super::process::SBProcess;
use super::stream::SBStream;
use super::watchpoint::SBWatchpoint;
use super::{DescriptionLevel, lldb_addr_t};
use sys;

/// The target program running under the debugger.
///
/// # Process Management
///
/// Starting a debug session is done by launching the target,
/// attaching to a running process, or loading a core file.
///
/// ## Launching
///
/// Launching a process can be done by creating and filling
/// out an [`SBLaunchInfo`] and calling [`launch`].
///
/// ```no_run
/// use lldb::*;
/// fn launch_target(target: &SBTarget) -> Result<SBProcess, SBError> {
///     let launch_info = SBLaunchInfo::new();
///     launch_info.set_launch_flags(LAUNCH_FLAG_STOP_AT_ENTRY);
///     // Probably want to set up a listener here.
///     target.launch(launch_info)
/// }
/// ```
///
/// ## Attaching
///
/// Attaching to a process can be done by creating and filling
/// out an [`SBAttachInfo`] and calling [`attach`].
///
/// ```no_run
/// use lldb::{lldb_pid_t, SBAttachInfo, SBError, SBProcess, SBTarget};
/// fn attach_to_pid(target: &SBTarget, pid: lldb_pid_t) -> Result<SBProcess, SBError> {
///     let attach_info = SBAttachInfo::new_with_pid(pid);
///     // Probably want to set up a listener here.
///     target.attach(attach_info)
/// }
/// ```
///
/// ## Core Files
///
/// ...
///
/// # Breakpoints and Watchpoints
///
/// ...
///
/// # Modules
///
/// ...
///
/// # Events
///
/// ...
///
/// [`SBLaunchInfo`]: struct.SBLaunchInfo.html
/// [`launch`]: #method.launch
/// [`SBAttachInfo`]: struct.SBAttachInfo.html
/// [`attach`]: #method.attach
pub struct SBTarget {
    /// The underlying raw `SBTargetRef`.
    pub raw: sys::SBTargetRef,
}

impl SBTarget {
    /// Construct a new `SBTarget`.
    pub fn wrap(raw: sys::SBTargetRef) -> SBTarget {
        SBTarget { raw: raw }
    }

    /// Construct a new `Some(SBTarget)` or `None`.
    pub fn maybe_wrap(raw: sys::SBTargetRef) -> Option<SBTarget> {
        if unsafe { sys::SBTargetIsValid(raw) != 0 } {
            Some(SBTarget { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBTarget` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBTargetIsValid(self.raw) != 0 }
    }

    /// Get the [`SBPlatform`] associated with this target.
    ///
    /// After return, the platform object should be checked for validity.
    ///
    /// [`SBPlatform`]: strut.SBPlatform.html
    pub fn platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBTargetGetPlatform(self.raw) } }
    }

    /// Get the [`SBProcess`] associated with this target.
    ///
    /// [`SBProcess`]: strut.SBProcess.html
    pub fn process(&self) -> SBProcess {
        unsafe { SBProcess { raw: sys::SBTargetGetProcess(self.raw) } }
    }

    /// Launch a target for debugging.
    pub fn launch(&self, launch_info: SBLaunchInfo) -> Result<SBProcess, SBError> {
        let error: SBError = SBError::new();
        let process =
            SBProcess::wrap(unsafe { sys::SBTargetLaunch2(self.raw, launch_info.raw, error.raw) });
        if error.is_success() {
            Ok(process)
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn attach(&self, attach_info: SBAttachInfo) -> Result<SBProcess, SBError> {
        let error: SBError = SBError::new();
        let process =
            SBProcess::wrap(unsafe { sys::SBTargetAttach(self.raw, attach_info.raw, error.raw) });
        if error.is_success() {
            Ok(process)
        } else {
            Err(error)
        }
    }

    /// Get a filespec for the executable.
    pub fn executable(&self) -> Option<SBFileSpec> {
        SBFileSpec::maybe_wrap(unsafe { sys::SBTargetGetExecutable(self.raw) })
    }

    /// Add a module to the target.
    pub fn add_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetAddModule(self.raw, module.raw) != 0 }
    }

    /// Add a module to the target using an `SBModuleSpec`.
    pub fn add_module_spec(&self, module_spec: &SBModuleSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetAddModule4(self.raw, module_spec.raw) })
    }

    /// Remove a module from the target.
    pub fn remove_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetRemoveModule(self.raw, module.raw) != 0 }
    }

    /// Get the debugger controlling this target.
    pub fn debugger(&self) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBTargetGetDebugger(self.raw) } }
    }

    /// Find the module for the given `SBFileSpec`.
    pub fn find_module(&self, file_spec: &SBFileSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetFindModule(self.raw, file_spec.raw) })
    }

    #[allow(missing_docs)]
    pub fn breakpoints(&self) -> SBTargetBreakpointIter {
        SBTargetBreakpointIter {
            target: self,
            idx: 0,
        }
    }

    #[allow(missing_docs)]
    pub fn delete_watchpoint(&self, watch_id: i32) {
        unsafe { sys::SBTargetDeleteWatchpoint(self.raw, watch_id) };
    }

    #[allow(missing_docs)]
    pub fn find_watchpoint_by_id(&self, watch_id: i32) -> Option<SBWatchpoint> {
        SBWatchpoint::maybe_wrap(unsafe { sys::SBTargetFindWatchpointByID(self.raw, watch_id) })
    }

    #[allow(missing_docs)]
    pub fn broadcaster(&self) -> SBBroadcaster {
        SBBroadcaster::wrap(unsafe { sys::SBTargetGetBroadcaster(self.raw) })
    }

    #[allow(missing_docs)]
    pub fn enable_all_watchpoints(&self) {
        unsafe { sys::SBTargetEnableAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn disable_all_watchpoints(&self) {
        unsafe { sys::SBTargetDisableAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn delete_all_watchpoints(&self) {
        unsafe { sys::SBTargetDeleteAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn watch_address(&self,
                         addr: lldb_addr_t,
                         size: usize,
                         read: bool,
                         write: bool)
                         -> Result<SBWatchpoint, SBError> {
        let error: SBError = SBError::new();
        let watchpoint = unsafe {
            sys::SBTargetWatchAddress(self.raw, addr, size, read as u8, write as u8, error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(watchpoint))
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn watchpoints(&self) -> SBTargetWatchpointIter {
        SBTargetWatchpointIter {
            target: self,
            idx: 0,
        }
    }
}

impl fmt::Debug for SBTarget {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBTargetGetDescription(self.raw, stream.raw, DescriptionLevel::Brief) };
        write!(fmt, "SBTarget {{ {} }}", stream.data())
    }
}

impl Drop for SBTarget {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBTarget(self.raw) };
    }
}

/// Iterate over the [breakpoints] in a [target].
///
/// [breakpoints]: struct.SBBreakpoint.html
/// [target]: struct.SBTarget.html
pub struct SBTargetBreakpointIter<'d> {
    target: &'d SBTarget,
    idx: usize,
}

impl<'d> Iterator for SBTargetBreakpointIter<'d> {
    type Item = SBBreakpoint;

    fn next(&mut self) -> Option<SBBreakpoint> {
        if self.idx < unsafe { sys::SBTargetGetNumBreakpoints(self.target.raw) as usize } {
            let r = Some(SBBreakpoint::wrap(unsafe {
                sys::SBTargetGetBreakpointAtIndex(self.target.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }
}

/// Iterate over the [watchpoints] in a [target].
///
/// [watchpoints]: struct.SBWatchpoint.html
/// [target]: struct.SBTarget.html
pub struct SBTargetWatchpointIter<'d> {
    target: &'d SBTarget,
    idx: usize,
}

impl<'d> Iterator for SBTargetWatchpointIter<'d> {
    type Item = SBWatchpoint;

    fn next(&mut self) -> Option<SBWatchpoint> {
        if self.idx < unsafe { sys::SBTargetGetNumWatchpoints(self.target.raw) as usize } {
            let r = Some(SBWatchpoint::wrap(unsafe {
                sys::SBTargetGetWatchpointAtIndex(self.target.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }
}
<commit_msg>Move function out of block of watchpoint functions.<commit_after>// 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.

use std::fmt;
use super::attachinfo::SBAttachInfo;
use super::breakpoint::SBBreakpoint;
use super::broadcaster::SBBroadcaster;
use super::debugger::SBDebugger;
use super::error::SBError;
use super::filespec::SBFileSpec;
use super::launchinfo::SBLaunchInfo;
use super::module::SBModule;
use super::modulespec::SBModuleSpec;
use super::platform::SBPlatform;
use super::process::SBProcess;
use super::stream::SBStream;
use super::watchpoint::SBWatchpoint;
use super::{DescriptionLevel, lldb_addr_t};
use sys;

/// The target program running under the debugger.
///
/// # Process Management
///
/// Starting a debug session is done by launching the target,
/// attaching to a running process, or loading a core file.
///
/// ## Launching
///
/// Launching a process can be done by creating and filling
/// out an [`SBLaunchInfo`] and calling [`launch`].
///
/// ```no_run
/// use lldb::*;
/// fn launch_target(target: &SBTarget) -> Result<SBProcess, SBError> {
///     let launch_info = SBLaunchInfo::new();
///     launch_info.set_launch_flags(LAUNCH_FLAG_STOP_AT_ENTRY);
///     // Probably want to set up a listener here.
///     target.launch(launch_info)
/// }
/// ```
///
/// ## Attaching
///
/// Attaching to a process can be done by creating and filling
/// out an [`SBAttachInfo`] and calling [`attach`].
///
/// ```no_run
/// use lldb::{lldb_pid_t, SBAttachInfo, SBError, SBProcess, SBTarget};
/// fn attach_to_pid(target: &SBTarget, pid: lldb_pid_t) -> Result<SBProcess, SBError> {
///     let attach_info = SBAttachInfo::new_with_pid(pid);
///     // Probably want to set up a listener here.
///     target.attach(attach_info)
/// }
/// ```
///
/// ## Core Files
///
/// ...
///
/// # Breakpoints and Watchpoints
///
/// ...
///
/// # Modules
///
/// ...
///
/// # Events
///
/// ...
///
/// [`SBLaunchInfo`]: struct.SBLaunchInfo.html
/// [`launch`]: #method.launch
/// [`SBAttachInfo`]: struct.SBAttachInfo.html
/// [`attach`]: #method.attach
pub struct SBTarget {
    /// The underlying raw `SBTargetRef`.
    pub raw: sys::SBTargetRef,
}

impl SBTarget {
    /// Construct a new `SBTarget`.
    pub fn wrap(raw: sys::SBTargetRef) -> SBTarget {
        SBTarget { raw: raw }
    }

    /// Construct a new `Some(SBTarget)` or `None`.
    pub fn maybe_wrap(raw: sys::SBTargetRef) -> Option<SBTarget> {
        if unsafe { sys::SBTargetIsValid(raw) != 0 } {
            Some(SBTarget { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBTarget` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBTargetIsValid(self.raw) != 0 }
    }

    /// Get the [`SBPlatform`] associated with this target.
    ///
    /// After return, the platform object should be checked for validity.
    ///
    /// [`SBPlatform`]: strut.SBPlatform.html
    pub fn platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBTargetGetPlatform(self.raw) } }
    }

    /// Get the [`SBProcess`] associated with this target.
    ///
    /// [`SBProcess`]: strut.SBProcess.html
    pub fn process(&self) -> SBProcess {
        unsafe { SBProcess { raw: sys::SBTargetGetProcess(self.raw) } }
    }

    /// Launch a target for debugging.
    pub fn launch(&self, launch_info: SBLaunchInfo) -> Result<SBProcess, SBError> {
        let error: SBError = SBError::new();
        let process =
            SBProcess::wrap(unsafe { sys::SBTargetLaunch2(self.raw, launch_info.raw, error.raw) });
        if error.is_success() {
            Ok(process)
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn attach(&self, attach_info: SBAttachInfo) -> Result<SBProcess, SBError> {
        let error: SBError = SBError::new();
        let process =
            SBProcess::wrap(unsafe { sys::SBTargetAttach(self.raw, attach_info.raw, error.raw) });
        if error.is_success() {
            Ok(process)
        } else {
            Err(error)
        }
    }

    /// Get a filespec for the executable.
    pub fn executable(&self) -> Option<SBFileSpec> {
        SBFileSpec::maybe_wrap(unsafe { sys::SBTargetGetExecutable(self.raw) })
    }

    /// Add a module to the target.
    pub fn add_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetAddModule(self.raw, module.raw) != 0 }
    }

    /// Add a module to the target using an `SBModuleSpec`.
    pub fn add_module_spec(&self, module_spec: &SBModuleSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetAddModule4(self.raw, module_spec.raw) })
    }

    /// Remove a module from the target.
    pub fn remove_module(&self, module: &SBModule) -> bool {
        unsafe { sys::SBTargetRemoveModule(self.raw, module.raw) != 0 }
    }

    /// Get the debugger controlling this target.
    pub fn debugger(&self) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBTargetGetDebugger(self.raw) } }
    }

    /// Find the module for the given `SBFileSpec`.
    pub fn find_module(&self, file_spec: &SBFileSpec) -> Option<SBModule> {
        SBModule::maybe_wrap(unsafe { sys::SBTargetFindModule(self.raw, file_spec.raw) })
    }

    #[allow(missing_docs)]
    pub fn breakpoints(&self) -> SBTargetBreakpointIter {
        SBTargetBreakpointIter {
            target: self,
            idx: 0,
        }
    }

    #[allow(missing_docs)]
    pub fn delete_watchpoint(&self, watch_id: i32) {
        unsafe { sys::SBTargetDeleteWatchpoint(self.raw, watch_id) };
    }

    #[allow(missing_docs)]
    pub fn find_watchpoint_by_id(&self, watch_id: i32) -> Option<SBWatchpoint> {
        SBWatchpoint::maybe_wrap(unsafe { sys::SBTargetFindWatchpointByID(self.raw, watch_id) })
    }

    #[allow(missing_docs)]
    pub fn enable_all_watchpoints(&self) {
        unsafe { sys::SBTargetEnableAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn disable_all_watchpoints(&self) {
        unsafe { sys::SBTargetDisableAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn delete_all_watchpoints(&self) {
        unsafe { sys::SBTargetDeleteAllWatchpoints(self.raw) };
    }

    #[allow(missing_docs)]
    pub fn watch_address(&self,
                         addr: lldb_addr_t,
                         size: usize,
                         read: bool,
                         write: bool)
                         -> Result<SBWatchpoint, SBError> {
        let error: SBError = SBError::new();
        let watchpoint = unsafe {
            sys::SBTargetWatchAddress(self.raw, addr, size, read as u8, write as u8, error.raw)
        };
        if error.is_success() {
            Ok(SBWatchpoint::wrap(watchpoint))
        } else {
            Err(error)
        }
    }

    #[allow(missing_docs)]
    pub fn watchpoints(&self) -> SBTargetWatchpointIter {
        SBTargetWatchpointIter {
            target: self,
            idx: 0,
        }
    }

    #[allow(missing_docs)]
    pub fn broadcaster(&self) -> SBBroadcaster {
        SBBroadcaster::wrap(unsafe { sys::SBTargetGetBroadcaster(self.raw) })
    }
}

impl fmt::Debug for SBTarget {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBTargetGetDescription(self.raw, stream.raw, DescriptionLevel::Brief) };
        write!(fmt, "SBTarget {{ {} }}", stream.data())
    }
}

impl Drop for SBTarget {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBTarget(self.raw) };
    }
}

/// Iterate over the [breakpoints] in a [target].
///
/// [breakpoints]: struct.SBBreakpoint.html
/// [target]: struct.SBTarget.html
pub struct SBTargetBreakpointIter<'d> {
    target: &'d SBTarget,
    idx: usize,
}

impl<'d> Iterator for SBTargetBreakpointIter<'d> {
    type Item = SBBreakpoint;

    fn next(&mut self) -> Option<SBBreakpoint> {
        if self.idx < unsafe { sys::SBTargetGetNumBreakpoints(self.target.raw) as usize } {
            let r = Some(SBBreakpoint::wrap(unsafe {
                sys::SBTargetGetBreakpointAtIndex(self.target.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }
}

/// Iterate over the [watchpoints] in a [target].
///
/// [watchpoints]: struct.SBWatchpoint.html
/// [target]: struct.SBTarget.html
pub struct SBTargetWatchpointIter<'d> {
    target: &'d SBTarget,
    idx: usize,
}

impl<'d> Iterator for SBTargetWatchpointIter<'d> {
    type Item = SBWatchpoint;

    fn next(&mut self) -> Option<SBWatchpoint> {
        if self.idx < unsafe { sys::SBTargetGetNumWatchpoints(self.target.raw) as usize } {
            let r = Some(SBWatchpoint::wrap(unsafe {
                sys::SBTargetGetWatchpointAtIndex(self.target.raw, self.idx as u32)
            }));
            self.idx += 1;
            r
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>#[crate_id = "tester"];

extern mod extra;
extern mod sdl;

use cpu::CPU;
use extra::getopts;
use extra::comm::DuplexStream;
use extra::arc::RWArc;

mod register;
mod mbc;
mod mmu;
mod cpu;
mod serial;
mod timer;
mod keypad;
mod gpu;
mod sound;

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::groups::optflag("s", "serial", "Output serial to stdout") ];
	let matches = match getopts::groups::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f.to_err_msg()); return }
	};

	let filename: ~str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::groups::usage(program, opts));
		return;
	};

	sdl::init([sdl::InitVideo]);
	sdl::wm::set_caption("RBoy - A gameboy in Rust", "rboy");
	let screen = match sdl::video::set_video_mode(160*2, 144*2, 32, [sdl::video::HWSurface], [sdl::video::DoubleBuf]) {
		Ok(screen) => screen,
		Err(err) => fail!("failed to open screen: {}", err),
	};

	let (sdlstream, cpustream) = DuplexStream::new();
	let rawscreen = ~[0xFFu8,.. 160*144*3];
	let arc = RWArc::new(rawscreen);
	let arc2 = arc.clone();
	spawn(proc() cpuloop(&cpustream, arc2, filename, &matches));

	'main : loop {
		match sdlstream.try_recv() {
			Some(_) => recalculate_screen(screen, &arc),
			None => {},
		}
		'event : loop {
			match sdl::event::poll_event() {
				sdl::event::QuitEvent => break 'main,
				sdl::event::NoEvent => break 'event,
				sdl::event::KeyEvent(sdl::event::EscapeKey, _, _, _)
					=> break 'main,
				sdl::event::KeyEvent(sdlkey, true, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyDown(key)),
						None => {},
					}
				},
				sdl::event::KeyEvent(sdlkey, false, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
	sdlstream.send(Poweroff);
}

fn sdl_to_keypad(key: sdl::event::Key) -> Option<keypad::KeypadKey> {
	match key {
		sdl::event::ZKey => Some(keypad::A),
		sdl::event::XKey => Some(keypad::B),
		sdl::event::UpKey => Some(keypad::Up),
		sdl::event::DownKey => Some(keypad::Down),
		sdl::event::LeftKey => Some(keypad::Left),
		sdl::event::RightKey => Some(keypad::Right),
		sdl::event::SpaceKey => Some(keypad::Select),
		sdl::event::ReturnKey => Some(keypad::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl::video::Surface, arc: &RWArc<~[u8]>) {
	arc.read(|data|
	for y in range(0, 144) {
		for x in range(0, 160) {
			screen.fill_rect(
				Some(sdl::Rect { x: (x*2) as i16, y: (y*2) as i16, w: 2, h: 2 }),
				sdl::video::RGB(data[y*160*3 + x*3 + 0],
				                data[y*160*3 + x*3 + 1],
				                data[y*160*3 + x*3 + 2])
			);
		}
	});
	screen.flip();
}

enum GBEvent {
	KeyUp(keypad::KeypadKey),
	KeyDown(keypad::KeypadKey),
	Poweroff,
}

fn cpuloop(channel: &DuplexStream<uint, GBEvent>, arc: RWArc<~[u8]>, filename: ~str, matches: &getopts::Matches) {
	let mut c = CPU::new(filename);
	c.mmu.serial.enabled = matches.opt_present("serial");

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(16);

	loop {
		c.cycle();

		if c.mmu.gpu.updated {
			c.mmu.gpu.updated = false;
			arc.write(|data|
				for i in range(0, c.mmu.gpu.data.len()) {
					data[i] = c.mmu.gpu.data[i];
				}
			);
			periodic.recv();
			channel.send(0);
		}

		match channel.try_recv() {
			None => {},
			Some(Poweroff) => { break; },
			Some(KeyUp(key)) => c.mmu.keypad.keyup(key),
			Some(KeyDown(key)) => c.mmu.keypad.keydown(key),
		};
	}
}
<commit_msg>Removed "sending on closed channel" failure<commit_after>#[crate_id = "tester"];

extern mod extra;
extern mod sdl;

use cpu::CPU;
use extra::getopts;
use extra::comm::DuplexStream;
use extra::arc::RWArc;

mod register;
mod mbc;
mod mmu;
mod cpu;
mod serial;
mod timer;
mod keypad;
mod gpu;
mod sound;

fn main() {
	let args: ~[~str] = std::os::args();
	let program = args[0].clone() + " <filename>";

	let opts = ~[ getopts::groups::optflag("s", "serial", "Output serial to stdout") ];
	let matches = match getopts::groups::getopts(args.tail(), opts) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f.to_err_msg()); return }
	};

	let filename: ~str = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		println!("{}", getopts::groups::usage(program, opts));
		return;
	};

	sdl::init([sdl::InitVideo]);
	sdl::wm::set_caption("RBoy - A gameboy in Rust", "rboy");
	let screen = match sdl::video::set_video_mode(160*2, 144*2, 32, [sdl::video::HWSurface], [sdl::video::DoubleBuf]) {
		Ok(screen) => screen,
		Err(err) => fail!("failed to open screen: {}", err),
	};

	let (sdlstream, cpustream) = DuplexStream::new();
	let rawscreen = ~[0xFFu8,.. 160*144*3];
	let arc = RWArc::new(rawscreen);
	let arc2 = arc.clone();
	spawn(proc() cpuloop(&cpustream, arc2, filename, &matches));

	'main : loop {
		match sdlstream.try_recv() {
			Some(_) => recalculate_screen(screen, &arc),
			None => {},
		}
		'event : loop {
			match sdl::event::poll_event() {
				sdl::event::QuitEvent => break 'main,
				sdl::event::NoEvent => break 'event,
				sdl::event::KeyEvent(sdl::event::EscapeKey, _, _, _)
					=> break 'main,
				sdl::event::KeyEvent(sdlkey, true, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyDown(key)),
						None => {},
					}
				},
				sdl::event::KeyEvent(sdlkey, false, _, _) => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => sdlstream.send(KeyUp(key)),
						None => {},
					}
				},
				_ => {}
			}
		}
	}
	sdlstream.send(Poweroff);
}

fn sdl_to_keypad(key: sdl::event::Key) -> Option<keypad::KeypadKey> {
	match key {
		sdl::event::ZKey => Some(keypad::A),
		sdl::event::XKey => Some(keypad::B),
		sdl::event::UpKey => Some(keypad::Up),
		sdl::event::DownKey => Some(keypad::Down),
		sdl::event::LeftKey => Some(keypad::Left),
		sdl::event::RightKey => Some(keypad::Right),
		sdl::event::SpaceKey => Some(keypad::Select),
		sdl::event::ReturnKey => Some(keypad::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl::video::Surface, arc: &RWArc<~[u8]>) {
	arc.read(|data|
	for y in range(0, 144) {
		for x in range(0, 160) {
			screen.fill_rect(
				Some(sdl::Rect { x: (x*2) as i16, y: (y*2) as i16, w: 2, h: 2 }),
				sdl::video::RGB(data[y*160*3 + x*3 + 0],
				                data[y*160*3 + x*3 + 1],
				                data[y*160*3 + x*3 + 2])
			);
		}
	});
	screen.flip();
}

enum GBEvent {
	KeyUp(keypad::KeypadKey),
	KeyDown(keypad::KeypadKey),
	Poweroff,
}

fn cpuloop(channel: &DuplexStream<uint, GBEvent>, arc: RWArc<~[u8]>, filename: ~str, matches: &getopts::Matches) {
	let mut c = CPU::new(filename);
	c.mmu.serial.enabled = matches.opt_present("serial");

	let mut timer = std::io::timer::Timer::new().unwrap();
	let periodic = timer.periodic(16);

	loop {
		c.cycle();

		if c.mmu.gpu.updated {
			c.mmu.gpu.updated = false;
			arc.write(|data|
				for i in range(0, c.mmu.gpu.data.len()) {
					data[i] = c.mmu.gpu.data[i];
				}
			);
			periodic.recv();
			channel.try_send(0);
		}

		match channel.try_recv() {
			None => {},
			Some(Poweroff) => { break; },
			Some(KeyUp(key)) => c.mmu.keypad.keyup(key),
			Some(KeyDown(key)) => c.mmu.keypad.keydown(key),
		};
	}
}
<|endoftext|>


<commit_before>use rand;
use std::fmt::Debug;
use std::thread;
use super::{Arbitrary, Gen, StdGen};
use tester::Status::{Discard, Fail, Pass};

/// The main QuickCheck type for setting configuration and running QuickCheck.
pub struct QuickCheck<G> {
    tests: usize,
    max_tests: usize,
    gen: G,
}

impl QuickCheck<StdGen<rand::ThreadRng>> {
    /// Creates a new QuickCheck value.
    ///
    /// This can be used to run QuickCheck on things that implement
    /// `Testable`. You may also adjust the configuration, such as
    /// the number of tests to run.
    ///
    /// By default, the maximum number of passed tests is set to `100`,
    /// the max number of overall tests is set to `10000` and the generator
    /// is set to a `StdGen` with a default size of `100`.
    pub fn new() -> QuickCheck<StdGen<rand::ThreadRng>> {
        QuickCheck {
            tests: 100,
            max_tests: 10000,
            gen: StdGen::new(rand::thread_rng(), 100),
        }
    }
}

impl<G: Gen> QuickCheck<G> {
    /// Set the number of tests to run.
    ///
    /// This actually refers to the maximum number of *passed* tests that
    /// can occur. Namely, if a test causes a failure, future testing on that
    /// property stops. Additionally, if tests are discarded, there may be
    /// fewer than `tests` passed.
    pub fn tests(mut self, tests: usize) -> QuickCheck<G> {
        self.tests = tests;
        self
    }

    /// Set the maximum number of tests to run.
    ///
    /// The number of invocations of a property will never exceed this number.
    /// This is necessary to cap the number of tests because QuickCheck
    /// properties can discard tests.
    pub fn max_tests(mut self, max_tests: usize) -> QuickCheck<G> {
        self.max_tests = max_tests;
        self
    }

    /// Set the random number generator to be used by QuickCheck.
    pub fn gen(mut self, gen: G) -> QuickCheck<G> {
        self.gen = gen;
        self
    }

    /// Tests a property and returns the result.
    ///
    /// The result returned is either the number of tests passed or a witness
    /// of failure.
    ///
    /// (If you're using Rust's unit testing infrastructure, then you'll
    /// want to use the `quickcheck` method, which will `panic!` on failure.)
    pub fn quicktest<A>(&mut self, f: A) -> Result<usize, TestResult>
                    where A: Testable {
        let mut ntests: usize = 0;
        for _ in 0..self.max_tests {
            if ntests >= self.tests {
                break
            }
            match f.result(&mut self.gen) {
                TestResult { status: Pass, .. } => ntests += 1,
                TestResult { status: Discard, .. } => continue,
                r @ TestResult { status: Fail, .. } => return Err(r),
            }
        }
        Ok(ntests)
    }

    /// Tests a property and calls `panic!` on failure.
    ///
    /// The `panic!` message will include a (hopefully) minimal witness of
    /// failure.
    ///
    /// It is appropriate to use this method with Rust's unit testing
    /// infrastructure.
    ///
    /// Note that if the environment variable `RUST_LOG` is set to enable
    /// `info` level log messages for the `quickcheck` crate, then this will
    /// include output on how many QuickCheck tests were passed.
    ///
    /// # Example
    ///
    /// ```rust
    /// use quickcheck::QuickCheck;
    ///
    /// fn prop_reverse_reverse() {
    ///     fn revrev(xs: Vec<usize>) -> bool {
    ///         let rev: Vec<_> = xs.clone().into_iter().rev().collect();
    ///         let revrev: Vec<_> = rev.into_iter().rev().collect();
    ///         xs == revrev
    ///     }
    ///     QuickCheck::new().quickcheck(revrev as fn(Vec<usize>) -> bool);
    /// }
    /// ```
    pub fn quickcheck<A>(&mut self, f: A) where A: Testable {
        // Ignore log init failures, implying it has already been done.
        let _ = ::env_logger::init();

        match self.quicktest(f) {
            Ok(ntests) => info!("(Passed {} QuickCheck tests.)", ntests),
            Err(result) => panic!(result.failed_msg()),
        }
    }
}

/// Convenience function for running QuickCheck.
///
/// This is an alias for `QuickCheck::new().quickcheck(f)`.
pub fn quickcheck<A: Testable>(f: A) { QuickCheck::new().quickcheck(f) }

/// Describes the status of a single instance of a test.
///
/// All testable things must be capable of producing a `TestResult`.
#[derive(Clone, Debug)]
pub struct TestResult {
    status: Status,
    arguments: Vec<String>,
    err: Option<String>,
}

/// Whether a test has passed, failed or been discarded.
#[derive(Clone, Debug)]
enum Status { Pass, Fail, Discard }

impl TestResult {
    /// Produces a test result that indicates the current test has passed.
    pub fn passed() -> TestResult { TestResult::from_bool(true) }

    /// Produces a test result that indicates the current test has failed.
    pub fn failed() -> TestResult { TestResult::from_bool(false) }

    /// Produces a test result that indicates failure from a runtime error.
    pub fn error<S: Into<String>>(msg: S) -> TestResult {
        let mut r = TestResult::from_bool(false);
        r.err = Some(msg.into());
        r
    }

    /// Produces a test result that instructs `quickcheck` to ignore it.
    /// This is useful for restricting the domain of your properties.
    /// When a test is discarded, `quickcheck` will replace it with a
    /// fresh one (up to a certain limit).
    pub fn discard() -> TestResult {
        TestResult {
            status: Discard,
            arguments: vec![],
            err: None,
        }
    }

    /// Converts a `bool` to a `TestResult`. A `true` value indicates that
    /// the test has passed and a `false` value indicates that the test
    /// has failed.
    pub fn from_bool(b: bool) -> TestResult {
        TestResult {
            status: if b { Pass } else { Fail },
            arguments: vec![],
            err: None,
        }
    }

    /// Tests if a "procedure" fails when executed. The test passes only if
    /// `f` generates a task failure during its execution.
    pub fn must_fail<T, F>(f: F) -> TestResult
            where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
        TestResult::from_bool(
            thread::Builder::new()
                            .spawn(move || { let _ = f(); })
                            .unwrap()
                            .join()
                            .is_err())
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test.
    pub fn is_failure(&self) -> bool {
        match self.status {
            Fail => true,
            Pass|Discard => false,
        }
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test as a result of a run time error.
    pub fn is_error(&self) -> bool {
        self.is_failure() && self.err.is_some()
    }

    fn failed_msg(&self) -> String {
        match self.err {
            None => {
                format!("[quickcheck] TEST FAILED. Arguments: ({})",
                        self.arguments.connect(", "))
            }
            Some(ref err) => {
                format!("[quickcheck] TEST FAILED (runtime error). \
                         Arguments: ({})\nError: {}",
                        self.arguments.connect(", "), err)
            }
        }
    }
}

/// `Testable` describes types (e.g., a function) whose values can be
/// tested.
///
/// Anything that can be tested must be capable of producing a `TestResult`
/// given a random number generator. This is trivial for types like `bool`,
/// which are just converted to either a passing or failing test result.
///
/// For functions, an implementation must generate random arguments
/// and potentially shrink those arguments if they produce a failure.
///
/// It's unlikely that you'll have to implement this trait yourself.
pub trait Testable : Send + 'static {
    fn result<G: Gen>(&self, &mut G) -> TestResult;
}

impl Testable for bool {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::from_bool(*self)
    }
}

impl Testable for () {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::passed()
    }
}

impl Testable for TestResult {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult { self.clone() }
}

impl<A, E> Testable for Result<A, E>
        where A: Testable, E: Debug + Send + 'static {
    fn result<G: Gen>(&self, g: &mut G) -> TestResult {
        match *self {
            Ok(ref r) => r.result(g),
            Err(ref err) => TestResult::error(format!("{:?}", err)),
        }
    }
}

macro_rules! testable_fn {
    ($($name: ident),*) => {

impl<T: Testable,
     $($name: Arbitrary + Debug),*> Testable for fn($($name),*) -> T {
    #[allow(non_snake_case)]
    fn result<G_: Gen>(&self, g: &mut G_) -> TestResult {
        fn shrink_failure<T: Testable, G_: Gen, $($name: Arbitrary + Debug),*>(
            g: &mut G_,
            self_: fn($($name),*) -> T,
            a: ($($name,)*),
        ) -> Option<TestResult> {
            for t in a.shrink() {
                let ($($name,)*) = t.clone();
                let mut r_new = safe(move || {self_($($name),*)}).result(g);
                if r_new.is_failure() {
                    let ($($name,)*) : ($($name,)*) = t.clone();
                    r_new.arguments = vec![$(format!("{:?}", $name),)*];

                    // The shrunk value *does* witness a failure, so keep
                    // trying to shrink it.
                    let shrunk = shrink_failure(g, self_, t);

                    // If we couldn't witness a failure on any shrunk value,
                    // then return the failure we already have.
                    return Some(shrunk.unwrap_or(r_new))
                }
            }
            None
        }

        let self_ = *self;
        let a: ($($name,)*) = Arbitrary::arbitrary(g);
        let ( $($name,)* ) = a.clone();
        let mut r = safe(move || {self_($($name),*)}).result(g);

        let ( $($name,)* ) = a.clone();
        r.arguments = vec![$(format!("{:?}", $name),)*];
        match r.status {
            Pass|Discard => r,
            Fail => {
                shrink_failure(g, self_, a).unwrap_or(r)
            }
        }
    }
}}}

testable_fn!();
testable_fn!(A);
testable_fn!(A, B);
testable_fn!(A, B, C);
testable_fn!(A, B, C, D);
testable_fn!(A, B, C, D, E);
testable_fn!(A, B, C, D, E, F);
testable_fn!(A, B, C, D, E, F, G);
testable_fn!(A, B, C, D, E, F, G, H);
testable_fn!(A, B, C, D, E, F, G, H, I);
testable_fn!(A, B, C, D, E, F, G, H, I, J);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K, L);

// TODO(burntsushi): Use `std::thread::catch_panic` once it stabilizes.
fn safe<T, F>(fun: F) -> Result<T, String>
        where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
    let t = ::std::thread::Builder::new().name("safe".into());
    t.spawn(fun).unwrap().join().map_err(|any_err| {
        // Extract common types of panic payload:
        // panic and assert produce &str or String
        if let Some(&s) = any_err.downcast_ref::<&str>() {
            s.to_owned()
        } else if let Some(s) = any_err.downcast_ref::<String>() {
            s.to_owned()
        } else {
            "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
        }
    })
}

/// Convenient aliases.
trait AShow : Arbitrary + Debug {}
impl<A: Arbitrary + Debug> AShow for A {}

#[cfg(test)]
mod test {
    use QuickCheck;

    #[test]
    fn shrinking_regression_issue_126() {
        fn thetest(vals: Vec<bool>) -> bool {
            vals.iter().filter(|&v| *v).count() < 2
        }
        let failing_case =
            QuickCheck::new()
            .quicktest(thetest as fn(vals: Vec<bool>) -> bool)
            .unwrap_err();
        let expected_argument = format!("{:?}", [true, true]);
        assert_eq!(failing_case.arguments, vec![expected_argument]);
    }
}
<commit_msg>Use catch_unwind instead of spawning a thread for every test.<commit_after>use std::fmt::Debug;
use std::panic;

use rand;

use tester::Status::{Discard, Fail, Pass};
use {Arbitrary, Gen, StdGen};

/// The main QuickCheck type for setting configuration and running QuickCheck.
pub struct QuickCheck<G> {
    tests: usize,
    max_tests: usize,
    gen: G,
}

impl QuickCheck<StdGen<rand::ThreadRng>> {
    /// Creates a new QuickCheck value.
    ///
    /// This can be used to run QuickCheck on things that implement
    /// `Testable`. You may also adjust the configuration, such as
    /// the number of tests to run.
    ///
    /// By default, the maximum number of passed tests is set to `100`,
    /// the max number of overall tests is set to `10000` and the generator
    /// is set to a `StdGen` with a default size of `100`.
    pub fn new() -> QuickCheck<StdGen<rand::ThreadRng>> {
        QuickCheck {
            tests: 100,
            max_tests: 10000,
            gen: StdGen::new(rand::thread_rng(), 100),
        }
    }
}

impl<G: Gen> QuickCheck<G> {
    /// Set the number of tests to run.
    ///
    /// This actually refers to the maximum number of *passed* tests that
    /// can occur. Namely, if a test causes a failure, future testing on that
    /// property stops. Additionally, if tests are discarded, there may be
    /// fewer than `tests` passed.
    pub fn tests(mut self, tests: usize) -> QuickCheck<G> {
        self.tests = tests;
        self
    }

    /// Set the maximum number of tests to run.
    ///
    /// The number of invocations of a property will never exceed this number.
    /// This is necessary to cap the number of tests because QuickCheck
    /// properties can discard tests.
    pub fn max_tests(mut self, max_tests: usize) -> QuickCheck<G> {
        self.max_tests = max_tests;
        self
    }

    /// Set the random number generator to be used by QuickCheck.
    pub fn gen(mut self, gen: G) -> QuickCheck<G> {
        self.gen = gen;
        self
    }

    /// Tests a property and returns the result.
    ///
    /// The result returned is either the number of tests passed or a witness
    /// of failure.
    ///
    /// (If you're using Rust's unit testing infrastructure, then you'll
    /// want to use the `quickcheck` method, which will `panic!` on failure.)
    pub fn quicktest<A>(&mut self, f: A) -> Result<usize, TestResult>
                    where A: Testable {
        let mut ntests: usize = 0;
        for _ in 0..self.max_tests {
            if ntests >= self.tests {
                break
            }
            match f.result(&mut self.gen) {
                TestResult { status: Pass, .. } => ntests += 1,
                TestResult { status: Discard, .. } => continue,
                r @ TestResult { status: Fail, .. } => return Err(r),
            }
        }
        Ok(ntests)
    }

    /// Tests a property and calls `panic!` on failure.
    ///
    /// The `panic!` message will include a (hopefully) minimal witness of
    /// failure.
    ///
    /// It is appropriate to use this method with Rust's unit testing
    /// infrastructure.
    ///
    /// Note that if the environment variable `RUST_LOG` is set to enable
    /// `info` level log messages for the `quickcheck` crate, then this will
    /// include output on how many QuickCheck tests were passed.
    ///
    /// # Example
    ///
    /// ```rust
    /// use quickcheck::QuickCheck;
    ///
    /// fn prop_reverse_reverse() {
    ///     fn revrev(xs: Vec<usize>) -> bool {
    ///         let rev: Vec<_> = xs.clone().into_iter().rev().collect();
    ///         let revrev: Vec<_> = rev.into_iter().rev().collect();
    ///         xs == revrev
    ///     }
    ///     QuickCheck::new().quickcheck(revrev as fn(Vec<usize>) -> bool);
    /// }
    /// ```
    pub fn quickcheck<A>(&mut self, f: A) where A: Testable {
        // Ignore log init failures, implying it has already been done.
        let _ = ::env_logger::init();

        match self.quicktest(f) {
            Ok(ntests) => info!("(Passed {} QuickCheck tests.)", ntests),
            Err(result) => panic!(result.failed_msg()),
        }
    }
}

/// Convenience function for running QuickCheck.
///
/// This is an alias for `QuickCheck::new().quickcheck(f)`.
pub fn quickcheck<A: Testable>(f: A) { QuickCheck::new().quickcheck(f) }

/// Describes the status of a single instance of a test.
///
/// All testable things must be capable of producing a `TestResult`.
#[derive(Clone, Debug)]
pub struct TestResult {
    status: Status,
    arguments: Vec<String>,
    err: Option<String>,
}

/// Whether a test has passed, failed or been discarded.
#[derive(Clone, Debug)]
enum Status { Pass, Fail, Discard }

impl TestResult {
    /// Produces a test result that indicates the current test has passed.
    pub fn passed() -> TestResult { TestResult::from_bool(true) }

    /// Produces a test result that indicates the current test has failed.
    pub fn failed() -> TestResult { TestResult::from_bool(false) }

    /// Produces a test result that indicates failure from a runtime error.
    pub fn error<S: Into<String>>(msg: S) -> TestResult {
        let mut r = TestResult::from_bool(false);
        r.err = Some(msg.into());
        r
    }

    /// Produces a test result that instructs `quickcheck` to ignore it.
    /// This is useful for restricting the domain of your properties.
    /// When a test is discarded, `quickcheck` will replace it with a
    /// fresh one (up to a certain limit).
    pub fn discard() -> TestResult {
        TestResult {
            status: Discard,
            arguments: vec![],
            err: None,
        }
    }

    /// Converts a `bool` to a `TestResult`. A `true` value indicates that
    /// the test has passed and a `false` value indicates that the test
    /// has failed.
    pub fn from_bool(b: bool) -> TestResult {
        TestResult {
            status: if b { Pass } else { Fail },
            arguments: vec![],
            err: None,
        }
    }

    /// Tests if a "procedure" fails when executed. The test passes only if
    /// `f` generates a task failure during its execution.
    pub fn must_fail<T, F>(f: F) -> TestResult
            where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
        let f = panic::AssertUnwindSafe(f);
        TestResult::from_bool(panic::catch_unwind(f).is_err())
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test.
    pub fn is_failure(&self) -> bool {
        match self.status {
            Fail => true,
            Pass|Discard => false,
        }
    }

    /// Returns `true` if and only if this test result describes a failing
    /// test as a result of a run time error.
    pub fn is_error(&self) -> bool {
        self.is_failure() && self.err.is_some()
    }

    fn failed_msg(&self) -> String {
        match self.err {
            None => {
                format!("[quickcheck] TEST FAILED. Arguments: ({})",
                        self.arguments.connect(", "))
            }
            Some(ref err) => {
                format!("[quickcheck] TEST FAILED (runtime error). \
                         Arguments: ({})\nError: {}",
                        self.arguments.connect(", "), err)
            }
        }
    }
}

/// `Testable` describes types (e.g., a function) whose values can be
/// tested.
///
/// Anything that can be tested must be capable of producing a `TestResult`
/// given a random number generator. This is trivial for types like `bool`,
/// which are just converted to either a passing or failing test result.
///
/// For functions, an implementation must generate random arguments
/// and potentially shrink those arguments if they produce a failure.
///
/// It's unlikely that you'll have to implement this trait yourself.
pub trait Testable : Send + 'static {
    fn result<G: Gen>(&self, &mut G) -> TestResult;
}

impl Testable for bool {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::from_bool(*self)
    }
}

impl Testable for () {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult {
        TestResult::passed()
    }
}

impl Testable for TestResult {
    fn result<G: Gen>(&self, _: &mut G) -> TestResult { self.clone() }
}

impl<A, E> Testable for Result<A, E>
        where A: Testable, E: Debug + Send + 'static {
    fn result<G: Gen>(&self, g: &mut G) -> TestResult {
        match *self {
            Ok(ref r) => r.result(g),
            Err(ref err) => TestResult::error(format!("{:?}", err)),
        }
    }
}

macro_rules! testable_fn {
    ($($name: ident),*) => {

impl<T: Testable,
     $($name: Arbitrary + Debug),*> Testable for fn($($name),*) -> T {
    #[allow(non_snake_case)]
    fn result<G_: Gen>(&self, g: &mut G_) -> TestResult {
        fn shrink_failure<T: Testable, G_: Gen, $($name: Arbitrary + Debug),*>(
            g: &mut G_,
            self_: fn($($name),*) -> T,
            a: ($($name,)*),
        ) -> Option<TestResult> {
            for t in a.shrink() {
                let ($($name,)*) = t.clone();
                let mut r_new = safe(move || {self_($($name),*)}).result(g);
                if r_new.is_failure() {
                    let ($($name,)*) : ($($name,)*) = t.clone();
                    r_new.arguments = vec![$(format!("{:?}", $name),)*];

                    // The shrunk value *does* witness a failure, so keep
                    // trying to shrink it.
                    let shrunk = shrink_failure(g, self_, t);

                    // If we couldn't witness a failure on any shrunk value,
                    // then return the failure we already have.
                    return Some(shrunk.unwrap_or(r_new))
                }
            }
            None
        }

        let self_ = *self;
        let a: ($($name,)*) = Arbitrary::arbitrary(g);
        let ( $($name,)* ) = a.clone();
        let mut r = safe(move || {self_($($name),*)}).result(g);

        let ( $($name,)* ) = a.clone();
        r.arguments = vec![$(format!("{:?}", $name),)*];
        match r.status {
            Pass|Discard => r,
            Fail => {
                shrink_failure(g, self_, a).unwrap_or(r)
            }
        }
    }
}}}

testable_fn!();
testable_fn!(A);
testable_fn!(A, B);
testable_fn!(A, B, C);
testable_fn!(A, B, C, D);
testable_fn!(A, B, C, D, E);
testable_fn!(A, B, C, D, E, F);
testable_fn!(A, B, C, D, E, F, G);
testable_fn!(A, B, C, D, E, F, G, H);
testable_fn!(A, B, C, D, E, F, G, H, I);
testable_fn!(A, B, C, D, E, F, G, H, I, J);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K);
testable_fn!(A, B, C, D, E, F, G, H, I, J, K, L);

fn safe<T, F>(fun: F) -> Result<T, String>
        where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static {
    panic::catch_unwind(panic::AssertUnwindSafe(fun)).map_err(|any_err| {
        // Extract common types of panic payload:
        // panic and assert produce &str or String
        if let Some(&s) = any_err.downcast_ref::<&str>() {
            s.to_owned()
        } else if let Some(s) = any_err.downcast_ref::<String>() {
            s.to_owned()
        } else {
            "UNABLE TO SHOW RESULT OF PANIC.".to_owned()
        }
    })
}

/// Convenient aliases.
trait AShow : Arbitrary + Debug {}
impl<A: Arbitrary + Debug> AShow for A {}

#[cfg(test)]
mod test {
    use QuickCheck;

    #[test]
    fn shrinking_regression_issue_126() {
        fn thetest(vals: Vec<bool>) -> bool {
            vals.iter().filter(|&v| *v).count() < 2
        }
        let failing_case =
            QuickCheck::new()
            .quicktest(thetest as fn(vals: Vec<bool>) -> bool)
            .unwrap_err();
        let expected_argument = format!("{:?}", [true, true]);
        assert_eq!(failing_case.arguments, vec![expected_argument]);
    }
}
<|endoftext|>


<commit_before>use super::{layout, callbacks, types, ids, development};

pub trait UiApplication {
    fn new_window(&mut self, title: &str, size: types::WindowStartSize, has_menu: bool) -> Box<UiWindow>;
    fn name<'a>(&'a self) -> ::std::borrow::Cow<'a, str>;
    fn start(&mut self);
    fn find_member_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiMember>;
    fn find_member_by_id(&self, id: ids::Id) -> Option<&UiMember>;
}

pub trait UiMember {
    fn size(&self) -> (u16, u16);
    fn on_resize(&mut self, Option<callbacks::Resize>);

    fn set_visibility(&mut self, visibility: types::Visibility);
    fn visibility(&self) -> types::Visibility;

    fn as_base(&self) -> &types::UiMemberBase;
    fn as_base_mut(&mut self) -> &mut types::UiMemberBase;

	fn is_control(&self) -> Option<&UiControl>;
    fn is_control_mut(&mut self) -> Option<&mut UiControl>;

    unsafe fn native_id(&self) -> usize;
}

pub trait UiLayable: UiMember {
	fn layout_width(&self) -> layout::Size;
	fn layout_height(&self) -> layout::Size;
	fn layout_gravity(&self) -> layout::Gravity;
	fn layout_orientation(&self) -> layout::Orientation;
	fn layout_alignment(&self) -> layout::Alignment;

	fn set_layout_width(&mut self, layout::Size);
	fn set_layout_height(&mut self, layout::Size);
	fn set_layout_gravity(&mut self, layout::Gravity);
	fn set_layout_orientation(&mut self, layout::Orientation);
	fn set_layout_alignment(&mut self, layout::Alignment);

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiControl: UiLayable + development::UiDrawable {
    fn is_container_mut(&mut self) -> Option<&mut UiContainer>;
    fn is_container(&self) -> Option<&UiContainer>;

	fn on_added_to_container(&mut self, &UiContainer, x: u16, y: u16);
    fn on_removed_from_container(&mut self, &UiContainer);

    fn parent(&self) -> Option<&types::UiMemberBase>;
    fn parent_mut(&mut self) -> Option<&mut types::UiMemberBase>;
    fn root(&self) -> Option<&types::UiMemberBase>;
    fn root_mut(&mut self) -> Option<&mut types::UiMemberBase>;

	fn as_layable(&self) -> &UiLayable;
	fn as_layable_mut(&mut self) -> &mut UiLayable;

    #[cfg(feature = "markup")]
    fn fill_from_markup(&mut self, &super::markup::Markup, &mut super::markup::MarkupRegistry);
}

pub trait UiContainer: UiMember {
    fn find_control_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiControl>;
    fn find_control_by_id(&self, id: ids::Id) -> Option<&UiControl>;

    fn is_multi_mut(&mut self) -> Option<&mut UiMultiContainer> { None }
    fn is_multi(&self) -> Option<&UiMultiContainer> { None }
    fn is_single_mut(&mut self) -> Option<&mut UiSingleContainer> { None }
    fn is_single(&self) -> Option<&UiSingleContainer> { None }

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiSingleContainer: UiContainer {
	fn set_child(&mut self, Option<Box<UiControl>>) -> Option<Box<UiControl>>;
    fn child(&self) -> Option<&UiControl>;
    fn child_mut(&mut self) -> Option<&mut UiControl>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;
}

pub trait UiMultiContainer: UiContainer {
    fn len(&self) -> usize;
    fn set_child_to(&mut self, index: usize, Box<UiControl>) -> Option<Box<UiControl>>;
    fn remove_child_from(&mut self, index: usize) -> Option<Box<UiControl>>;
    fn child_at(&self, index: usize) -> Option<&Box<UiControl>>;
    fn child_at_mut(&mut self, index: usize) -> Option<&mut Box<UiControl>>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;

    fn clear(&mut self) {
        let len = self.len();
        for index in (0..len).rev() {
            self.remove_child_from(index);
        }
    }
    fn push_child(&mut self, child: Box<UiControl>) {
        let len = self.len();
        self.set_child_to(len, child);
    }
    fn pop_child(&mut self) -> Option<Box<UiControl>> {
        let len = self.len();
        if len > 0 {
        	self.remove_child_from(len - 1)
        } else {
        	None
        }
    }
}

pub trait UiWindow: UiSingleContainer {
	fn as_single_container(&self) -> &UiSingleContainer;
	fn as_single_container_mut(&mut self) -> &mut UiSingleContainer;
}

pub trait UiButton: UiControl {
    //fn new(label: &str) -> Box<Self>;
    fn label(&self) -> &str;
    fn set_label(&mut self, &str);
    fn on_left_click(&mut self, Option<callbacks::Click>);

	fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
}

pub trait UiLinearLayout: UiMultiContainer + UiControl {
    fn orientation(&self) -> layout::Orientation;
    fn set_orientation(&mut self, layout::Orientation);

	fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
	fn as_multi_container(&self) -> &UiMultiContainer;
	fn as_multi_container_mut(&mut self) -> &mut UiMultiContainer;
}

pub trait UiRelativeLayout: UiMultiContainer + UiControl {}<commit_msg>Traits reorganization<commit_after>use super::{layout, callbacks, types, ids, development};

pub trait UiApplication {
    fn new_window(&mut self, title: &str, size: types::WindowStartSize, has_menu: bool) -> Box<UiWindow>;
    fn name<'a>(&'a self) -> ::std::borrow::Cow<'a, str>;
    fn start(&mut self);
    fn find_member_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiMember>;
    fn find_member_by_id(&self, id: ids::Id) -> Option<&UiMember>;
}

pub trait UiMember {
    fn size(&self) -> (u16, u16);
    fn on_resize(&mut self, Option<callbacks::Resize>);

    fn set_visibility(&mut self, visibility: types::Visibility);
    fn visibility(&self) -> types::Visibility;

    fn as_base(&self) -> &types::UiMemberBase;
    fn as_base_mut(&mut self) -> &mut types::UiMemberBase;

	fn is_control(&self) -> Option<&UiControl>;
    fn is_control_mut(&mut self) -> Option<&mut UiControl>;

    unsafe fn native_id(&self) -> usize;
}

pub trait UiHasLayout: UiMember {
	fn layout_width(&self) -> layout::Size;
	fn layout_height(&self) -> layout::Size;
	fn layout_gravity(&self) -> layout::Gravity;
	fn layout_orientation(&self) -> layout::Orientation;
	fn layout_alignment(&self) -> layout::Alignment;

	fn set_layout_width(&mut self, layout::Size);
	fn set_layout_height(&mut self, layout::Size);
	fn set_layout_gravity(&mut self, layout::Gravity);
	fn set_layout_orientation(&mut self, layout::Orientation);
	fn set_layout_alignment(&mut self, layout::Alignment);

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiControl: UiHasLayout + development::UiDrawable {
    fn is_container_mut(&mut self) -> Option<&mut UiContainer>;
    fn is_container(&self) -> Option<&UiContainer>;

	fn on_added_to_container(&mut self, &UiContainer, x: u16, y: u16);
    fn on_removed_from_container(&mut self, &UiContainer);

    fn parent(&self) -> Option<&types::UiMemberBase>;
    fn parent_mut(&mut self) -> Option<&mut types::UiMemberBase>;
    fn root(&self) -> Option<&types::UiMemberBase>;
    fn root_mut(&mut self) -> Option<&mut types::UiMemberBase>;

    #[cfg(feature = "markup")]
    fn fill_from_markup(&mut self, &super::markup::Markup, &mut super::markup::MarkupRegistry);

	fn as_has_layout(&self) -> &UiHasLayout;
	fn as_has_layout_mut(&mut self) -> &mut UiHasLayout;

	/*fn as_drawable(&self) -> &development::UiDrawable;
	fn as_drawable_mut(&mut self) -> &mut development::UiDrawable;	*/
}

pub trait UiContainer: UiMember {
    fn find_control_by_id_mut(&mut self, id: ids::Id) -> Option<&mut UiControl>;
    fn find_control_by_id(&self, id: ids::Id) -> Option<&UiControl>;

    fn is_multi_mut(&mut self) -> Option<&mut UiMultiContainer> { None }
    fn is_multi(&self) -> Option<&UiMultiContainer> { None }
    fn is_single_mut(&mut self) -> Option<&mut UiSingleContainer> { None }
    fn is_single(&self) -> Option<&UiSingleContainer> { None }

	fn as_member(&self) -> &UiMember;
	fn as_member_mut(&mut self) -> &mut UiMember;
}

pub trait UiSingleContainer: UiContainer {
	fn set_child(&mut self, Option<Box<UiControl>>) -> Option<Box<UiControl>>;
    fn child(&self) -> Option<&UiControl>;
    fn child_mut(&mut self) -> Option<&mut UiControl>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;
}

pub trait UiMultiContainer: UiContainer {
    fn len(&self) -> usize;
    fn set_child_to(&mut self, index: usize, Box<UiControl>) -> Option<Box<UiControl>>;
    fn remove_child_from(&mut self, index: usize) -> Option<Box<UiControl>>;
    fn child_at(&self, index: usize) -> Option<&Box<UiControl>>;
    fn child_at_mut(&mut self, index: usize) -> Option<&mut Box<UiControl>>;

	fn as_container(&self) -> &UiContainer;
	fn as_container_mut(&mut self) -> &mut UiContainer;

    fn clear(&mut self) {
        let len = self.len();
        for index in (0..len).rev() {
            self.remove_child_from(index);
        }
    }
    fn push_child(&mut self, child: Box<UiControl>) {
        let len = self.len();
        self.set_child_to(len, child);
    }
    fn pop_child(&mut self) -> Option<Box<UiControl>> {
        let len = self.len();
        if len > 0 {
        	self.remove_child_from(len - 1)
        } else {
        	None
        }
    }
}

pub trait UiHasLabel {
	fn label<'a>(&'a self) -> ::std::borrow::Cow<'a, str>;
    fn set_label(&mut self, &str);
}

pub trait UiClickable {
	fn on_click(&mut self, Option<callbacks::Click>);
}

pub trait UiWindow: UiSingleContainer + UiHasLabel {
	fn as_single_container(&self) -> &UiSingleContainer;
	fn as_single_container_mut(&mut self) -> &mut UiSingleContainer;
}

pub trait UiButton: UiControl + UiClickable + UiHasLabel {
    fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
	fn as_clickable(&self) -> &UiClickable;
	fn as_clickable_mut(&mut self) -> &mut UiClickable;
	fn as_has_label(&self) -> &UiHasLabel;
	fn as_has_label_mut(&mut self) -> &mut UiHasLabel;
}

pub trait UiLinearLayout: UiMultiContainer + UiControl {
    fn orientation(&self) -> layout::Orientation;
    fn set_orientation(&mut self, layout::Orientation);

	fn as_control(&self) -> &UiControl;
	fn as_control_mut(&mut self) -> &mut UiControl;
	fn as_multi_container(&self) -> &UiMultiContainer;
	fn as_multi_container_mut(&mut self) -> &mut UiMultiContainer;
}

pub trait UiRelativeLayout: UiMultiContainer + UiControl {}<|endoftext|>