<commit_before>use std::map::HashMap;
use syntax::ast;
use ast::{ty, pat};
use syntax::codemap::{span};
use syntax::visit;
use syntax::print;

fn indent<R>(op: fn() -> R) -> R {
    // Use in conjunction with the log post-processor like `src/etc/indenter`
    // to make debug output more readable.
    debug!(">>");
    let r <- op();
    debug!("<< (Result = %?)", r);
    move r
}

struct _indenter {
    _i: (),
    drop { debug!("<<"); }
}

fn _indenter(_i: ()) -> _indenter {
    _indenter {
        _i: ()
    }
}

fn indenter() -> _indenter {
    debug!(">>");
    _indenter(())
}

type flag = HashMap<~str, ()>;

fn field_expr(f: ast::field) -> @ast::expr { return f.node.expr; }

fn field_exprs(fields: ~[ast::field]) -> ~[@ast::expr] {
    let mut es = ~[];
    for fields.each |f| { es.push(f.node.expr); }
    return es;
}

// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
    let rs = @mut false;
    let visit_expr =
        |e: @ast::expr, &&flag: @mut bool, v: visit::vt<@mut bool>| {
        *flag |= p(e.node);
        match e.node {
          // Skip inner loops, since a break in the inner loop isn't a
          // break inside the outer loop
          ast::expr_loop(*) | ast::expr_while(*)
          | ast::expr_loop_body(*) => {}
          _ => visit::visit_expr(e, flag, v)
        }
    };
    let v = visit::mk_vt(@{visit_expr: visit_expr
                           ,.. *visit::default_visitor()});
    visit::visit_block(b, rs, v);
    return *rs;
}

fn has_nonlocal_exits(b: ast::blk) -> bool {
    do loop_query(b) |e| {
        match e {
          ast::expr_break(_) | ast::expr_again(_) => true,
          _ => false
        }
    }
}

fn may_break(b: ast::blk) -> bool {
    do loop_query(b) |e| {
        match e {
          ast::expr_break(_) => true,
          _ => false
        }
    }
}

fn local_rhs_span(l: @ast::local, def: span) -> span {
    match l.node.init {
      Some(i) => return i.expr.span,
      _ => return def
    }
}

fn is_main_name(path: syntax::ast_map::path) -> bool {
    // FIXME (#34): path should be a constrained type, so we know
    // the call to last doesn't fail.
    vec::last(path) == syntax::ast_map::path_name(
        syntax::parse::token::special_idents::main
    )
}

fn pluralize(n: uint, s: ~str) -> ~str {
    if n == 1 { s }
    else { str::concat([s, ~"s"]) }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Remove obsolete FIXME<commit_after>use std::map::HashMap;
use syntax::ast;
use ast::{ty, pat};
use syntax::codemap::{span};
use syntax::visit;
use syntax::print;

fn indent<R>(op: fn() -> R) -> R {
    // Use in conjunction with the log post-processor like `src/etc/indenter`
    // to make debug output more readable.
    debug!(">>");
    let r <- op();
    debug!("<< (Result = %?)", r);
    move r
}

struct _indenter {
    _i: (),
    drop { debug!("<<"); }
}

fn _indenter(_i: ()) -> _indenter {
    _indenter {
        _i: ()
    }
}

fn indenter() -> _indenter {
    debug!(">>");
    _indenter(())
}

type flag = HashMap<~str, ()>;

fn field_expr(f: ast::field) -> @ast::expr { return f.node.expr; }

fn field_exprs(fields: ~[ast::field]) -> ~[@ast::expr] {
    let mut es = ~[];
    for fields.each |f| { es.push(f.node.expr); }
    return es;
}

// Takes a predicate p, returns true iff p is true for any subexpressions
// of b -- skipping any inner loops (loop, while, loop_body)
fn loop_query(b: ast::blk, p: fn@(ast::expr_) -> bool) -> bool {
    let rs = @mut false;
    let visit_expr =
        |e: @ast::expr, &&flag: @mut bool, v: visit::vt<@mut bool>| {
        *flag |= p(e.node);
        match e.node {
          // Skip inner loops, since a break in the inner loop isn't a
          // break inside the outer loop
          ast::expr_loop(*) | ast::expr_while(*)
          | ast::expr_loop_body(*) => {}
          _ => visit::visit_expr(e, flag, v)
        }
    };
    let v = visit::mk_vt(@{visit_expr: visit_expr
                           ,.. *visit::default_visitor()});
    visit::visit_block(b, rs, v);
    return *rs;
}

fn has_nonlocal_exits(b: ast::blk) -> bool {
    do loop_query(b) |e| {
        match e {
          ast::expr_break(_) | ast::expr_again(_) => true,
          _ => false
        }
    }
}

fn may_break(b: ast::blk) -> bool {
    do loop_query(b) |e| {
        match e {
          ast::expr_break(_) => true,
          _ => false
        }
    }
}

fn local_rhs_span(l: @ast::local, def: span) -> span {
    match l.node.init {
      Some(i) => return i.expr.span,
      _ => return def
    }
}

fn is_main_name(path: syntax::ast_map::path) -> bool {
    vec::last(path) == syntax::ast_map::path_name(
        syntax::parse::token::special_idents::main
    )
}

fn pluralize(n: uint, s: ~str) -> ~str {
    if n == 1 { s }
    else { str::concat([s, ~"s"]) }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>//! A module providing an enum for a message prefix.
use std::string;
use std::str::FromStr;
use std::fmt;

/// The Prefix indicates "the true origin of the message", according to the server.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Prefix {
    /// servername, e.g. collins.mozilla.org
    ServerName(String),
    /// nickname [ ["!" username] "@" hostname ]
    /// i.e. Nickname(nickname, username, hostname)
    /// Any of the strings may be ""
    Nickname(String, String, String),
}

impl Prefix {
    /// Creates a prefix by parsing a string.
    ///
    /// # Example
    /// ```
    /// # extern crate irc_proto;
    /// # use irc_proto::Prefix;
    /// # fn main() {
    /// Prefix::new_from_str("nickname!username@hostname");
    /// Prefix::new_from_str("example.com");
    /// # }
    /// ```
    pub fn new_from_str(s: &str) -> Prefix {
        #[derive(Copy, Clone, Eq, PartialEq)]
        enum Active {
            Name,
            User,
            Host,
        }

        let mut name = String::new();
        let mut user = String::new();
        let mut host = String::new();
        let mut active = Active::Name;
        let mut is_server = false;

        for c in s.chars() {
            if c == '.' && active == Active::Name {
                // We won't return Nickname("nick", "", "") but if @ or ! are
                // encountered, then we set this back to false
                is_server = true;
            }

            match c {
                '!' if active == Active::Name => {
                    is_server = false;
                    active = Active::User;
                },

                '@' if active != Active::Host => {
                    is_server = false;
                    active = Active::Host;
                },

                _ => {
                    // Push onto the active buffer
                    match active {
                        Active::Name => &mut name,
                        Active::User => &mut user,
                        Active::Host => &mut host,
                    }.push(c)
                }
            }
        }

        if is_server {
            Prefix::ServerName(name)
        } else {
            Prefix::Nickname(name, user, host)
        }
    }
}

/// This implementation never returns an error and is isomorphic with `Display`.
impl FromStr for Prefix {
    type Err = string::ParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Prefix::new_from_str(s))
    }
}

/// This is isomorphic with `FromStr`
impl fmt::Display for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Prefix::ServerName(name) => write!(f, "{}", name),
            Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) {
                ("", "", "") => write!(f, ""),
                (name, "", "") => write!(f, "{}", name),
                (name, user, "") => write!(f, "{}!{}", name, user),
                (name, "", host) => write!(f, "{}@{}", name, host),
                (name, user, host) => write!(f, "{}!{}@{}", name, user, host),
            },
        }
    }
}

impl<'a> From<&'a str> for Prefix {
    fn from(s: &str) -> Self {
        Prefix::new_from_str(s)
    }
}

#[cfg(test)]
mod test {
    use super::Prefix::{self, ServerName, Nickname};

    // Checks that str -> parsed -> Display doesn't lose data
    fn test_parse(s: &str) -> Prefix {
        let prefix = Prefix::new_from_str(s);
        let s2 = format!("{}", prefix);
        assert_eq!(s, &s2);
        prefix
    }

    #[test]
    fn print() {
        let s = format!("{}", Nickname("nick".into(), "".into(), "".into()));
        assert_eq!(&s, "nick");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "".into()));
        assert_eq!(&s, "nick!user");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into()));
        assert_eq!(&s, "nick!user@host");
    }

    #[test]
    fn parse_word() {
        assert_eq!(
            test_parse("only_nick"),
            Nickname("only_nick".into(), String::new(), String::new())
        )
    }

    #[test]
    fn parse_host() {
        assert_eq!(
            test_parse("host.tld"),
            ServerName("host.tld".into())
        )
    }

    #[test]
    fn parse_nick_user() {
        assert_eq!(
            test_parse("test!nick"),
            Nickname("test".into(), "nick".into(), String::new())
        )
    }

    #[test]
    fn parse_nick_user_host() {
        assert_eq!(
            test_parse("test!nick@host"),
            Nickname("test".into(), "nick".into(), "host".into())
        )
    }

    #[test]
    fn parse_dot_and_symbols() {
        assert_eq!(
            test_parse("test.net@something"),
            Nickname("test.net".into(), "".into(), "something".into())
        )
    }

    #[test]
    fn parse_danger_cases() {
        assert_eq!(
            test_parse("name@name!user"),
            Nickname("name".into(), "".into(), "name!user".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@hostname".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "hostname".into())
        );
        assert_eq!(
            test_parse("name!.user"),
            Nickname("name".into(), ".user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user.user"),
            Nickname("name".into(), "user.user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user@host.host"),
            Nickname("name".into(), "user".into(), "host.host".into())
        );
        assert_eq!(
            test_parse("!user"),
            Nickname("".into(), "user".into(), "".into())
        );
        assert_eq!(
            "!@host.host".parse::<Prefix>().unwrap(),
            Nickname("".into(), "".into(), "host.host".into())
        );
    }
}
<commit_msg>ParseError -> ()<commit_after>//! A module providing an enum for a message prefix.
use std::str::FromStr;
use std::fmt;

/// The Prefix indicates "the true origin of the message", according to the server.
#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Prefix {
    /// servername, e.g. collins.mozilla.org
    ServerName(String),
    /// nickname [ ["!" username] "@" hostname ]
    /// i.e. Nickname(nickname, username, hostname)
    /// Any of the strings may be ""
    Nickname(String, String, String),
}

impl Prefix {
    /// Creates a prefix by parsing a string.
    ///
    /// # Example
    /// ```
    /// # extern crate irc_proto;
    /// # use irc_proto::Prefix;
    /// # fn main() {
    /// Prefix::new_from_str("nickname!username@hostname");
    /// Prefix::new_from_str("example.com");
    /// # }
    /// ```
    pub fn new_from_str(s: &str) -> Prefix {
        #[derive(Copy, Clone, Eq, PartialEq)]
        enum Active {
            Name,
            User,
            Host,
        }

        let mut name = String::new();
        let mut user = String::new();
        let mut host = String::new();
        let mut active = Active::Name;
        let mut is_server = false;

        for c in s.chars() {
            if c == '.' && active == Active::Name {
                // We won't return Nickname("nick", "", "") but if @ or ! are
                // encountered, then we set this back to false
                is_server = true;
            }

            match c {
                '!' if active == Active::Name => {
                    is_server = false;
                    active = Active::User;
                },

                '@' if active != Active::Host => {
                    is_server = false;
                    active = Active::Host;
                },

                _ => {
                    // Push onto the active buffer
                    match active {
                        Active::Name => &mut name,
                        Active::User => &mut user,
                        Active::Host => &mut host,
                    }.push(c)
                }
            }
        }

        if is_server {
            Prefix::ServerName(name)
        } else {
            Prefix::Nickname(name, user, host)
        }
    }
}

/// This implementation never returns an error and is isomorphic with `Display`.
impl FromStr for Prefix {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Ok(Prefix::new_from_str(s))
    }
}

/// This is isomorphic with `FromStr`
impl fmt::Display for Prefix {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Prefix::ServerName(name) => write!(f, "{}", name),
            Prefix::Nickname(name, user, host) => match (&name[..], &user[..], &host[..]) {
                ("", "", "") => write!(f, ""),
                (name, "", "") => write!(f, "{}", name),
                (name, user, "") => write!(f, "{}!{}", name, user),
                (name, "", host) => write!(f, "{}@{}", name, host),
                (name, user, host) => write!(f, "{}!{}@{}", name, user, host),
            },
        }
    }
}

impl<'a> From<&'a str> for Prefix {
    fn from(s: &str) -> Self {
        Prefix::new_from_str(s)
    }
}

#[cfg(test)]
mod test {
    use super::Prefix::{self, ServerName, Nickname};

    // Checks that str -> parsed -> Display doesn't lose data
    fn test_parse(s: &str) -> Prefix {
        let prefix = Prefix::new_from_str(s);
        let s2 = format!("{}", prefix);
        assert_eq!(s, &s2);
        prefix
    }

    #[test]
    fn print() {
        let s = format!("{}", Nickname("nick".into(), "".into(), "".into()));
        assert_eq!(&s, "nick");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "".into()));
        assert_eq!(&s, "nick!user");
        let s = format!("{}", Nickname("nick".into(), "user".into(), "host".into()));
        assert_eq!(&s, "nick!user@host");
    }

    #[test]
    fn parse_word() {
        assert_eq!(
            test_parse("only_nick"),
            Nickname("only_nick".into(), String::new(), String::new())
        )
    }

    #[test]
    fn parse_host() {
        assert_eq!(
            test_parse("host.tld"),
            ServerName("host.tld".into())
        )
    }

    #[test]
    fn parse_nick_user() {
        assert_eq!(
            test_parse("test!nick"),
            Nickname("test".into(), "nick".into(), String::new())
        )
    }

    #[test]
    fn parse_nick_user_host() {
        assert_eq!(
            test_parse("test!nick@host"),
            Nickname("test".into(), "nick".into(), "host".into())
        )
    }

    #[test]
    fn parse_dot_and_symbols() {
        assert_eq!(
            test_parse("test.net@something"),
            Nickname("test.net".into(), "".into(), "something".into())
        )
    }

    #[test]
    fn parse_danger_cases() {
        assert_eq!(
            test_parse("name@name!user"),
            Nickname("name".into(), "".into(), "name!user".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "".into())
        );
        assert_eq!(
            // can't reverse the parse
            "name!@hostname".parse::<Prefix>().unwrap(),
            Nickname("name".into(), "".into(), "hostname".into())
        );
        assert_eq!(
            test_parse("name!.user"),
            Nickname("name".into(), ".user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user.user"),
            Nickname("name".into(), "user.user".into(), "".into())
        );
        assert_eq!(
            test_parse("name!user@host.host"),
            Nickname("name".into(), "user".into(), "host.host".into())
        );
        assert_eq!(
            test_parse("!user"),
            Nickname("".into(), "user".into(), "".into())
        );
        assert_eq!(
            "!@host.host".parse::<Prefix>().unwrap(),
            Nickname("".into(), "".into(), "host.host".into())
        );
    }
}
<|endoftext|>


<commit_before>use std::libc::{c_ulonglong};
use std::vec::{with_capacity, append};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[doc(hidden)]
pub fn marshal<T>(buf: &[u8],
                  padbefore: uint,
                  bytestodrop: uint,
                  f: &fn(*mut u8, *u8, c_ulonglong) -> T
                 ) -> (~[u8], T) {
    let mut dst = with_capacity(buf.len() + padbefore);
    for _ in range(0, padbefore) {
        dst.push(0);
    }
    dst = append(dst, buf);
    let pdst = to_mut_ptr(dst);
    let psrc = to_ptr(dst);
    let res = f(pdst, psrc, dst.len() as c_ulonglong);
    for _ in range(0, bytestodrop) {
        dst.shift();
    }
    (dst, res)
}
<commit_msg>Optimized marshal function<commit_after>use std::libc::{c_ulonglong};
use std::vec::{with_capacity, append};
use std::vec::raw::{to_mut_ptr, to_ptr};

#[doc(hidden)]
pub fn marshal<T>(buf: &[u8],
                  padbefore: uint,
                  bytestodrop: uint,
                  f: &fn(*mut u8, *u8, c_ulonglong) -> T
                 ) -> (~[u8], T) {
    let mut dst = with_capacity(buf.len() + padbefore);
    for _ in range(0, padbefore) {
        dst.push(0);
    }
    dst = append(dst, buf);
    let pdst = to_mut_ptr(dst);
    let psrc = to_ptr(dst);
    let res = f(pdst, psrc, dst.len() as c_ulonglong);
    (dst.move_iter().skip(bytestodrop).collect(), res)
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Simon Sapin.
//
// 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.

//! Parser and serializer for the [`application/x-www-form-urlencoded` format](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use std::str;

use encoding;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;

use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};

/// Convert a string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
#[inline]
pub fn parse_str(input: &str) -> Vec<(String, String)> {
    parse_bytes(input.as_bytes(), None, false, false).unwrap()
}

/// Convert a byte string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
/// * `isindex`: The *isindex flag*. If in doubt, set to `false`.
pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
                   mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
    let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
    let mut pairs = Vec::new();
    for piece in input.split(|&b| b == b'&') {
        if piece.is_empty() {
            if isindex {
                pairs.push((Vec::new(), Vec::new()))
            }
        } else {
            let (name, value) = match piece.position_elem(&b'=') {
                Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
                None => if isindex { ([].as_slice(), piece) } else { (piece, [].as_slice()) }
            };
            let name = replace_plus(name);
            let value = replace_plus(value);
            if use_charset && name.as_slice() == b"_charset_" {
                // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
                match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
                    Some(encoding) => encoding_override = encoding,
                    None => (),
                }
                use_charset = false;
            }
            pairs.push((name, value));
        }
        isindex = false;
    }
    if encoding_override.name() != "utf-8" && !input.is_ascii() {
        return None
    }

    #[inline]
    fn replace_plus(input: &[u8]) -> Vec<u8> {
        input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
    }

    #[inline]
    fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
        encoding_override.decode(
            percent_decode(input.as_slice()).as_slice(),
            encoding::DecodeReplace).unwrap()
    }

    Some(pairs.move_iter().map(
        |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
    ).collect())
}

/// Convert a slice of owned (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
#[inline]
pub fn serialize_owned(pairs: &[(String, String)]) -> String {
    serialize(pairs.iter().map(|&(ref n, ref v)| (n.as_slice(), v.as_slice())), None)
}

/// Convert an iterator of (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is encoded as
///    before percent-encoding. Defaults to UTF-8.
pub fn serialize<'a, I: Iterator<(&'a str, &'a str)>>(
        mut pairs: I, encoding_override: Option<EncodingRef>)
        -> String {
    #[inline]
    fn byte_serialize(input: &str, output: &mut String,
                      encoding_override: Option<EncodingRef>) {
        let keep_alive;
        let input = match encoding_override {
            None => input.as_bytes(),  // "Encode" to UTF-8
            Some(encoding) => {
                keep_alive = encoding.encode(input, encoding::EncodeNcrEscape).unwrap();
                keep_alive.as_slice()
            }
        };

        for &byte in input.iter() {
            if byte == b' ' {
                output.push_str("+")
            } else {
                percent_encode_to([byte], FORM_URLENCODED_ENCODE_SET, output)
            }
        }
    }

    let mut output = String::new();
    for (name, value) in pairs {
        if output.len() > 0 {
            output.push_str("&");
            byte_serialize(name, &mut output, encoding_override);
            output.push_str("=");
            byte_serialize(value, &mut output, encoding_override);
        }
    }
    output
}
<commit_msg>Fix #19: application/x-www-form-urlencoded serialization was broken.<commit_after>// Copyright 2013-2014 Simon Sapin.
//
// 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.

//! Parser and serializer for the [`application/x-www-form-urlencoded` format](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use std::str;

use encoding;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;

use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};

/// Convert a string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
#[inline]
pub fn parse_str(input: &str) -> Vec<(String, String)> {
    parse_bytes(input.as_bytes(), None, false, false).unwrap()
}

/// Convert a byte string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
/// * `isindex`: The *isindex flag*. If in doubt, set to `false`.
pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
                   mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
    let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
    let mut pairs = Vec::new();
    for piece in input.split(|&b| b == b'&') {
        if piece.is_empty() {
            if isindex {
                pairs.push((Vec::new(), Vec::new()))
            }
        } else {
            let (name, value) = match piece.position_elem(&b'=') {
                Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
                None => if isindex { ([].as_slice(), piece) } else { (piece, [].as_slice()) }
            };
            let name = replace_plus(name);
            let value = replace_plus(value);
            if use_charset && name.as_slice() == b"_charset_" {
                // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
                match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
                    Some(encoding) => encoding_override = encoding,
                    None => (),
                }
                use_charset = false;
            }
            pairs.push((name, value));
        }
        isindex = false;
    }
    if encoding_override.name() != "utf-8" && !input.is_ascii() {
        return None
    }

    #[inline]
    fn replace_plus(input: &[u8]) -> Vec<u8> {
        input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
    }

    #[inline]
    fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
        encoding_override.decode(
            percent_decode(input.as_slice()).as_slice(),
            encoding::DecodeReplace).unwrap()
    }

    Some(pairs.move_iter().map(
        |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
    ).collect())
}

/// Convert a slice of owned (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
#[inline]
pub fn serialize_owned(pairs: &[(String, String)]) -> String {
    serialize(pairs.iter().map(|&(ref n, ref v)| (n.as_slice(), v.as_slice())), None)
}

/// Convert an iterator of (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is encoded as
///    before percent-encoding. Defaults to UTF-8.
pub fn serialize<'a, I: Iterator<(&'a str, &'a str)>>(
        mut pairs: I, encoding_override: Option<EncodingRef>)
        -> String {
    #[inline]
    fn byte_serialize(input: &str, output: &mut String,
                      encoding_override: Option<EncodingRef>) {
        let keep_alive;
        let input = match encoding_override {
            None => input.as_bytes(),  // "Encode" to UTF-8
            Some(encoding) => {
                keep_alive = encoding.encode(input, encoding::EncodeNcrEscape).unwrap();
                keep_alive.as_slice()
            }
        };

        for &byte in input.iter() {
            if byte == b' ' {
                output.push_str("+")
            } else {
                percent_encode_to([byte], FORM_URLENCODED_ENCODE_SET, output)
            }
        }
    }

    let mut output = String::new();
    for (name, value) in pairs {
        if output.len() > 0 {
            output.push_str("&");
        }
        byte_serialize(name, &mut output, encoding_override);
        output.push_str("=");
        byte_serialize(value, &mut output, encoding_override);
    }
    output
}

#[test]
fn test_form_urlencoded() {
    let pairs = [
        ("foo".to_string(), "é&".to_string()),
        ("bar".to_string(), "".to_string()),
        ("foo".to_string(), "#".to_string())
    ];
    let encoded = serialize_owned(pairs.as_slice());
    assert_eq!(encoded.as_slice(), "foo=%C3%A9%26&bar=&foo=%23");
    assert_eq!(parse_str(encoded.as_slice()), Vec::from_slice(pairs.as_slice()));
}
<|endoftext|>


<commit_before>//! Handles example propagation.

use common::*;
use data::{Data, Sample};

/// Result of trying to force a sample positive/negative.
pub enum ForceRes {
    /// Failure.
    None,
    /// Sample was classified as positive.
    Pos { sample: Sample, clause: ClsIdx },
    /// Sample was classified as negative.
    Neg { sample: Sample, clause: ClsIdx },
}

/// Propagates examples, tries to break implication constraints.
pub struct Assistant {
    /// Core, to communicate with the teacher.
    // core: & 'a MsgCore,
    /// Solver.
    solver: Solver<()>,
    /// Instance.
    instance: Arc<Instance>,
    /// Positive constraints.
    pos: PrdHMap<ClsSet>,
    /// Negative constraints.
    neg: PrdHMap<ClsSet>,
    /// Profiler.
    _profiler: Profiler,
    /// True if we're using ADTs.
    using_adts: bool,
}

impl Assistant {
    /// Constructor.
    pub fn new(instance: Arc<Instance> // core: & 'a MsgCore
        ) -> Res<Self> {
        let solver = conf.solver.spawn("assistant", (), &instance)?;
        let _profiler = Profiler::new();

        let mut pos = PrdHMap::with_capacity(instance.preds().len());
        let mut neg = PrdHMap::with_capacity(instance.preds().len());

        let mut pos_clauses = ClsSet::new();
        let mut neg_clauses = ClsSet::new();

        let using_adts = dtyp::get_all().iter().next().is_some();

        macro_rules! add_clauses {
            ($pred:expr) => {{
                if !pos_clauses.is_empty() {
                    let mut clause_set = ClsSet::new();
                    ::std::mem::swap(&mut pos_clauses, &mut clause_set);
                    let prev = pos.insert($pred, clause_set);
                    debug_assert! { prev.is_none() }
                }
                if !neg_clauses.is_empty() {
                    let mut clause_set = ClsSet::new();
                    ::std::mem::swap(&mut neg_clauses, &mut clause_set);
                    let prev = neg.insert($pred, clause_set);
                    debug_assert! { prev.is_none() }
                }
            }};
        }

        for pred in instance.pred_indices() {
            debug_assert! { pos_clauses.is_empty() }
            debug_assert! { neg_clauses.is_empty() }

            for clause in instance.clauses_of(pred).1 {
                let clause = *clause;
                if instance[clause].lhs_preds().is_empty() {
                    let is_new = pos_clauses.insert(clause);
                    debug_assert! { is_new }
                }
            }

            for clause in instance.clauses_of(pred).0 {
                let clause = *clause;
                if instance[clause].rhs().is_none() && instance[clause].lhs_pred_apps_len() == 1 {
                    let is_new = neg_clauses.insert(clause);
                    debug_assert! { is_new }
                }
            }

            add_clauses!(pred)
        }

        Ok(Assistant {
            // core,
            solver,
            instance,
            pos,
            neg,
            _profiler,
            using_adts,
        })
    }

    /// Destroys the assistant.
    pub fn finalize(mut self) -> Res<Profiler> {
        self.solver.kill().chain_err(|| "While killing solver")?;
        Ok(self._profiler)
    }

    /// Breaks implications.
    pub fn break_implications(&mut self, data: &mut Data) -> Res<()> {
        if data.constraints.is_empty() {
            return Ok(());
        }

        let (mut pos, mut neg) = (Vec::new(), Vec::new());
        // msg! { debug self.core => "breaking implications..." }
        profile! { self "constraints received" => add data.constraints.len() }

        'all_constraints: for cstr in CstrRange::zero_to(data.constraints.len()) {
            // Can happen because of simplifications when propagating.
            if cstr > data.constraints.len() {
                break;
            }
            if data.constraints[cstr].is_tautology() {
                continue;
            }

            // debug! {
            //   "  {}", data.constraints[cstr].string_do(
            //     self.instance.preds(), |s| s.to_string()
            //   ).unwrap()
            // }

            let mut trivial = false;
            let mut rhs_false = false;
            let mut lhs_unknown = 0;
            macro_rules! move_on {
                (if trivial) => {
                    if trivial {
                        move_on!()
                    }
                };
                () => {{
                    if trivial || lhs_unknown == 0 || rhs_false && lhs_unknown == 1 {
                        profile! { self "constraints   broken" => add 1 }
                    }
                    // Discard the constraint, regardless of what will happen.
                    profile! { self tick "data" }
                    data.tautologize(cstr)?;
                    for (Sample { pred, args }, clause) in pos.drain(0..) {
                        data.add_pos(clause, pred, args);
                    }
                    for (Sample { pred, args }, clause) in neg.drain(0..) {
                        data.add_neg(clause, pred, args);
                    }
                    data.propagate()?;
                    profile! { self mark "data" }
                    continue 'all_constraints;
                }};
            }

            if let Some(&Sample { pred, ref args }) = data.constraints[cstr].rhs() {
                match self.try_force(data, pred, args)? {
                    ForceRes::None => (),
                    ForceRes::Pos { sample, clause } => {
                        pos.push((sample, clause));
                        // Constraint is trivial, move on.
                        trivial = true
                    }
                    ForceRes::Neg { sample, clause } => {
                        rhs_false = true;
                        neg.push((sample, clause))
                    }
                }
            }

            // move_on!(if trivial) ;

            if let Some(lhs) = data.constraints[cstr].lhs() {
                for (pred, samples) in lhs {
                    let mut lhs_trivial = true;
                    for sample in samples {
                        match self.try_force(data, *pred, sample)? {
                            ForceRes::None => {
                                lhs_unknown += 1;
                                lhs_trivial = false
                            }
                            ForceRes::Pos { sample, clause } => pos.push((sample, clause)),
                            ForceRes::Neg { sample, clause } => {
                                neg.push((sample, clause));
                                trivial = true;
                                // Constraint is trivial, move on.
                                // break 'lhs
                            }
                        }
                    }
                    trivial = trivial || lhs_trivial
                }
            } else {
                bail!("Illegal constraint")
            }

            move_on!()
        }

        let (_pos_count, _neg_count) = data.pos_neg_count();
        if !data.pos.is_empty() {
            profile! { self "positive examples generated" => add _pos_count }
        }
        if !data.neg.is_empty() {
            profile! { self "negative examples generated" => add _neg_count }
        }

        Ok(())
    }

    /// Checks if a sample can be forced to anything.
    ///
    /// If it can't, return None. If it can, returns
    ///
    /// - `ForceRes::Pos` of a sample which, when forced positive, will force the
    ///   input sample to be classified positive.
    /// - `ForceRes::Neg` of a sample which, when forced negative, will force the
    ///   input sample to be classified negative.
    pub fn try_force(&mut self, _data: &Data, pred: PrdIdx, vals: &VarVals) -> Res<ForceRes> {
        self.solver.comment_args(format_args!(
            "working on sample ({} {})",
            self.instance[pred], vals
        ))?;

        if let Some(clauses) = self.pos.get(&pred) {
            self.solver.comment("working on positive clauses")?;

            for clause_idx in clauses {
                let clause_idx = *clause_idx;
                let clause = &self.instance[clause_idx];
                if let Some((p, args)) = clause.rhs() {
                    debug_assert_eq! { pred, p }
                    debug_assert! { clause.lhs_preds().is_empty() }

                    if self.using_adts {
                        smt::reset(&mut self.solver, &self.instance)?
                    } else {
                        self.solver.push(1)?
                    }

                    clause.declare(&mut self.solver)?;
                    self.solver.assert(&ConjWrap::new(clause.lhs_terms()))?;

                    self.solver.assert(&ArgValEq::new(args, vals))?;
                    let sat = profile! {
                      self wrap {
                        self.solver.check_sat() ?
                      } "smt"
                    };

                    if self.using_adts {
                        smt::reset(&mut self.solver, &self.instance)?
                    } else {
                        self.solver.pop(1)?
                    }

                    if sat {
                        // msg! { debug self => "  forcing positive" }
                        return Ok(ForceRes::Pos {
                            sample: Sample {
                                pred,
                                args: vals.clone(),
                            },
                            clause: clause_idx,
                        });
                    }
                } else {
                    bail!("inconsistent instance state")
                }
            }
        }

        if let Some(clauses) = self.neg.get(&pred) {
            self.solver.comment("working on negative clauses")?;

            for clause_idx in clauses {
                let clause_idx = *clause_idx;
                let clause = &self.instance[clause_idx];
                if let Some(argss) = clause.lhs_preds().get(&pred) {
                    let args = {
                        let mut argss = argss.iter();
                        if let Some(args) = argss.next() {
                            debug_assert! { argss.next().is_none() }
                            args
                        } else {
                            bail!("inconsistent instance state")
                        }
                    };

                    if self.using_adts {
                        smt::reset(&mut self.solver, &self.instance)?
                    } else {
                        self.solver.push(1)?
                    }

                    clause.declare(&mut self.solver)?;
                    self.solver.assert(&ConjWrap::new(clause.lhs_terms()))?;
                    self.solver.assert(&ArgValEq::new(args, vals))?;
                    let sat = profile! {
                      self wrap {
                        self.solver.check_sat() ?
                      } "smt"
                    };

                    if self.using_adts {
                        smt::reset(&mut self.solver, &self.instance)?
                    } else {
                        self.solver.pop(1)?
                    }

                    if sat {
                        // msg! { debug self => "  forcing negative" }
                        return Ok(ForceRes::Neg {
                            sample: Sample {
                                pred,
                                args: vals.clone(),
                            },
                            clause: clause_idx,
                        });
                    }
                } else {
                    bail!("inconsistent instance state")
                }
            }
        }

        Ok(ForceRes::None)
    }
}

/// Wrapper around a conjunction for smt printing.
struct ConjWrap<'a> {
    /// Conjunction.
    terms: &'a TermSet,
}
impl<'a> ConjWrap<'a> {
    /// Constructor.
    pub fn new(terms: &'a TermSet) -> Self {
        ConjWrap { terms }
    }
}
impl<'a> Expr2Smt<()> for ConjWrap<'a> {
    fn expr_to_smt2<Writer: Write>(&self, w: &mut Writer, _: ()) -> SmtRes<()> {
        if self.terms.is_empty() {
            write!(w, "true")?
        } else {
            write!(w, "(and")?;
            for term in self.terms {
                write!(w, " ")?;
                term.write(w, |w, var| var.default_write(w))?;
            }
            write!(w, ")")?
        }
        Ok(())
    }
}

/// Wrapper around some arguments and some values.
///
/// Used to assert `(= arg[i] val[i])`.
pub struct ArgValEq<'a> {
    /// Arguments.
    args: &'a VarTerms,
    /// Values.
    vals: &'a VarVals,
}
impl<'a> ArgValEq<'a> {
    /// Constructor.
    pub fn new(args: &'a VarTerms, vals: &'a VarVals) -> Self {
        debug_assert_eq! { args.len(), vals.len() }
        ArgValEq { args, vals }
    }
}
impl<'a> Expr2Smt<()> for ArgValEq<'a> {
    fn expr_to_smt2<Writer>(&self, w: &mut Writer, _: ()) -> ::rsmt2::SmtRes<()>
    where
        Writer: Write,
    {
        write!(w, "(and")?;
        let mut unknown = 0;

        for (arg, val) in self.args.iter().zip(self.vals.iter()) {
            if !val.is_known() {
                unknown += 1;
                continue;
            }

            match val.get() {
                val::RVal::B(b) => {
                    write!(w, " ")?;
                    if !b {
                        write!(w, "(not ")?
                    }
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    if !b {
                        write!(w, ")")?
                    }
                }

                val::RVal::I(ref i) => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " ")?;
                    int_to_smt!(w, i)?;
                    write!(w, ")")?
                }

                val::RVal::R(ref r) => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " ")?;
                    rat_to_smt!(w, r)?;
                    write!(w, ")")?
                }

                val::RVal::Array { .. } | val::RVal::DTypNew { .. } => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " {})", val)?
                }

                val::RVal::N(_) => (),
            }
        }

        if unknown == self.args.len() {
            write!(w, " true")?
        }
        write!(w, ")")?;
        Ok(())
    }
}
<commit_msg>assistant can now generalize samples (make them more partial)<commit_after>//! Handles example propagation.

use common::*;
use data::{Data, Sample};

/// Result of trying to force a sample positive/negative.
pub enum ForceRes {
    /// Failure.
    None,
    /// Sample was classified as positive.
    Pos { sample: Sample, clause: ClsIdx },
    /// Sample was classified as negative.
    Neg { sample: Sample, clause: ClsIdx },
}

/// Stores data from a positive / strict negative clause.
///
/// # Examples
///
/// If the clause is `forall x, y | x > 0 => p(x + 1, y)` then the data stored is
///
/// |      |                          |
/// |:----:|:-------------------------|
/// | conj | `x > 0`                  |
/// | args | `v_0 -> x + 1, v_1 -> y` |
/// | vars | `v_0`                    |
#[derive(Clone, Debug)]
pub struct ClauseData {
    /// Index of the clause.
    pub idx: ClsIdx,
    /// Conjunction of lhs terms.
    pub conj: Term,
    /// Map from the clause's **only** predicate to the clause's variables.
    pub args: VarTerms,
    /// Variables of the predicate that are relevant w.r.t. `conj`. None if all are relevant.
    pub vars: Option<VarSet>,
    /// True if the clause is a positive one.
    pub pos: bool,
}
impl ClauseData {
    /// Constructor.
    pub fn new(idx: ClsIdx, pos: bool, args: &VarTerms, lhs_terms: &TermSet) -> Self {
        let conj = term::and(lhs_terms.iter().cloned().collect());
        let args = args.clone();
        let conj_vars = term::vars(&conj);

        let mut vars = VarSet::new();
        for (pred_var, arg) in args.index_iter() {
            if let Some(var) = arg.var_idx() {
                if !conj_vars.contains(&var) {
                    continue;
                }
            }
            let is_new = vars.insert(pred_var);
            debug_assert! { is_new }
        }
        let vars = if vars.len() == args.len() {
            None
        } else {
            Some(vars)
        };

        ClauseData {
            idx,
            conj,
            args,
            vars,
            pos,
        }
    }
}

/// Propagates examples, tries to break implication constraints.
pub struct Assistant {
    /// Core, to communicate with the teacher.
    // core: & 'a MsgCore,
    /// Solver.
    solver: Solver<()>,
    /// Instance.
    instance: Arc<Instance>,
    /// Profiler.
    _profiler: Profiler,
    /// True if we're using ADTs.
    using_adts: bool,
    /// Maps predicates to their positive / strict negative clause data.
    clauses: PrdHMap<Vec<ClauseData>>,
}

impl Assistant {
    /// Constructor.
    pub fn new(instance: Arc<Instance>) -> Res<Self> {
        let solver = conf.solver.spawn("assistant", (), &instance)?;
        let _profiler = Profiler::new();

        let using_adts = dtyp::get_all().iter().next().is_some();

        let clauses = PrdHMap::new();

        let mut res = Assistant {
            // core,
            solver,
            instance,
            _profiler,
            using_adts,
            clauses,
        };

        res.register_clauses()?;

        Ok(res)
    }

    /// Registers all positive / strict negative clauses.
    fn register_clauses(&mut self) -> Res<()> {
        let instance = self.instance.clone();
        for clause_idx in instance.pos_clauses() {
            let clause = &instance[*clause_idx];

            debug_assert! { clause.lhs_preds().is_empty() }

            if let Some((pred, args)) = clause.rhs() {
                self.register(*clause_idx, pred, args, clause.lhs_terms(), true)
            } else {
                bail!("inconsistent positive clause set from instance")
            }
        }

        for clause_idx in instance.strict_neg_clauses() {
            let clause = &instance[*clause_idx];

            debug_assert! { clause.rhs().is_none() }
            debug_assert! { clause.lhs_preds().len() == 1 }

            if let Some((pred, argss)) = clause.lhs_preds().iter().next() {
                debug_assert! { argss.len() == 1 }

                if let Some(args) = argss.iter().next() {
                    self.register(*clause_idx, *pred, args, clause.lhs_terms(), false)
                } else {
                    bail!("inconsistent clause state")
                }
            } else {
                bail!("inconsistent strict negative clause set from instance")
            }
        }

        Ok(())
    }

    /// Registers some clause data for a predicate.
    ///
    /// Boolean flag indicates whether the original clause is positive or not.
    fn register(
        &mut self,
        idx: ClsIdx,
        pred: PrdIdx,
        args: &VarTerms,
        lhs_terms: &TermSet,
        pos: bool,
    ) {
        let data = ClauseData::new(idx, pos, args, lhs_terms);
        self.clauses.entry(pred).or_insert_with(Vec::new).push(data)
    }

    /// Destroys the assistant.
    pub fn finalize(mut self) -> Res<Profiler> {
        self.solver.kill().chain_err(|| "While killing solver")?;
        Ok(self._profiler)
    }

    /// Breaks implications.
    pub fn break_implications(&mut self, data: &mut Data) -> Res<()> {
        if data.constraints.is_empty() {
            return Ok(());
        }

        let (mut pos, mut neg) = (Vec::new(), Vec::new());
        // msg! { debug self.core => "breaking implications..." }
        profile! { self "constraints received" => add data.constraints.len() }

        'all_constraints: for cstr in CstrRange::zero_to(data.constraints.len()) {
            // Can happen because of simplifications when propagating.
            if cstr > data.constraints.len() {
                break;
            }
            if data.constraints[cstr].is_tautology() {
                continue;
            }

            // debug! {
            //   "  {}", data.constraints[cstr].string_do(
            //     self.instance.preds(), |s| s.to_string()
            //   ).unwrap()
            // }

            let mut trivial = false;
            let mut rhs_false = false;
            let mut lhs_unknown = 0;
            macro_rules! move_on {
                (if trivial) => {
                    if trivial {
                        move_on!()
                    }
                };
                () => {{
                    if trivial || lhs_unknown == 0 || rhs_false && lhs_unknown == 1 {
                        profile! { self "constraints   broken" => add 1 }
                    }

                    // Discard the constraint, regardless of what will happen.
                    profile! { self tick "data" }
                    data.tautologize(cstr)?;
                    for (Sample { pred, args }, clause) in pos.drain(0..) {
                        data.add_pos(clause, pred, args);
                    }
                    for (Sample { pred, args }, clause) in neg.drain(0..) {
                        data.add_neg(clause, pred, args);
                    }
                    data.propagate()?;
                    profile! { self mark "data" }
                    continue 'all_constraints;
                }};
            }

            if let Some(&Sample { pred, ref args }) = data.constraints[cstr].rhs() {
                match self.try_force(data, pred, args)? {
                    ForceRes::None => (),
                    ForceRes::Pos { sample, clause } => {
                        pos.push((sample, clause));
                        // Constraint is trivial, move on.
                        trivial = true
                    }
                    ForceRes::Neg { sample, clause } => {
                        rhs_false = true;
                        neg.push((sample, clause))
                    }
                }
            }

            // move_on!(if trivial) ;

            if let Some(lhs) = data.constraints[cstr].lhs() {
                for (pred, samples) in lhs {
                    let mut lhs_trivial = true;
                    for sample in samples {
                        match self.try_force(data, *pred, sample)? {
                            ForceRes::None => {
                                lhs_unknown += 1;
                                lhs_trivial = false
                            }
                            ForceRes::Pos { sample, clause } => pos.push((sample, clause)),
                            ForceRes::Neg { sample, clause } => {
                                neg.push((sample, clause));
                                trivial = true;
                                // Constraint is trivial, move on.
                                // break 'lhs
                            }
                        }
                    }
                    trivial = trivial || lhs_trivial
                }
            } else {
                bail!("Illegal constraint")
            }

            move_on!()
        }

        let (_pos_count, _neg_count) = data.pos_neg_count();
        if !data.pos.is_empty() {
            profile! { self "positive examples generated" => add _pos_count }
        }
        if !data.neg.is_empty() {
            profile! { self "negative examples generated" => add _neg_count }
        }

        Ok(())
    }

    /// Checks if a sample can be forced to anything.
    ///
    /// If it can't, return None. If it can, returns
    ///
    /// - `ForceRes::Pos` of a sample which, when forced positive, will force the
    ///   input sample to be classified positive.
    /// - `ForceRes::Neg` of a sample which, when forced negative, will force the
    ///   input sample to be classified negative.
    pub fn try_force(&mut self, _data: &Data, pred: PrdIdx, vals: &VarVals) -> Res<ForceRes> {
        let clause_data = if let Some(data) = self.clauses.get(&pred) {
            data
        } else {
            return Ok(ForceRes::None);
        };

        self.solver.comment_args(format_args!(
            "working on sample ({} {})",
            self.instance[pred], vals
        ))?;

        macro_rules! solver {
            (push) => {
                if !self.using_adts {
                    self.solver.push(1)?
                }
            };
            (pop) => {
                if self.using_adts {
                    smt::reset(&mut self.solver, &self.instance)?
                } else {
                    self.solver.pop(1)?
                }
            };
        }

        for ClauseData {
            idx,
            conj,
            args,
            vars,
            pos,
        } in clause_data
        {
            self.solver.comment_args(format_args!(
                "working on positive clauses with lhs {}",
                conj
            ))?;

            let clause = *idx;

            solver!(push);

            self.instance[clause].declare(&mut self.solver)?;

            self.solver.assert(&smt::SmtTerm::new(conj))?;
            self.solver
                .assert(&ArgValEq::new(args, vals, vars.as_ref()))?;

            let sat = profile! {
                self wrap { self.solver.check_sat() } "smt"
            }?;

            solver!(pop);

            if sat {
                let args = if let Some(vars) = vars {
                    let mut nu_vals = var_to::vals::RVarVals::with_capacity(vals.len());
                    for (idx, val) in vals.index_iter() {
                        if vars.contains(&idx) {
                            nu_vals.push(val.clone())
                        } else {
                            nu_vals.push(val::none(val.typ()))
                        }
                    }
                    var_to::vals::new(nu_vals)
                } else {
                    vals.clone()
                };

                self.solver.comment_args(format_args!(
                    "success, yielding {} sample ({} {})",
                    if *pos { "positive" } else { "negative" },
                    self.instance[pred],
                    args
                ))?;

                let sample = Sample { pred, args };

                if *pos {
                    return Ok(ForceRes::Pos { sample, clause });
                } else {
                    return Ok(ForceRes::Neg { sample, clause });
                }
            }
        }

        Ok(ForceRes::None)
    }
}

/// Wrapper around some arguments and some values.
///
/// Used to assert `(= arg[i] val[i])`.
pub struct ArgValEq<'a> {
    /// Arguments.
    args: &'a VarTerms,
    /// Values.
    vals: &'a VarVals,
    /// Only assert equalities for variables that are in this set. Assert all if none.
    vars: Option<&'a VarSet>,
}
impl<'a> ArgValEq<'a> {
    /// Constructor.
    pub fn new(args: &'a VarTerms, vals: &'a VarVals, vars: Option<&'a VarSet>) -> Self {
        debug_assert_eq! { args.len(), vals.len() }
        ArgValEq { args, vals, vars }
    }
}
impl<'a> Expr2Smt<()> for ArgValEq<'a> {
    fn expr_to_smt2<Writer>(&self, w: &mut Writer, _: ()) -> ::rsmt2::SmtRes<()>
    where
        Writer: Write,
    {
        write!(w, "(and")?;
        let mut skipped = 0;

        for ((var, arg), val) in self.args.index_iter().zip(self.vals.iter()) {
            // Skip if variable has no value, or the set of variables to assert does not contain
            // it.
            if !val.is_known() || self.vars.map(|set| !set.contains(&var)).unwrap_or(false) {
                skipped += 1;
                continue;
            }

            match val.get() {
                val::RVal::B(b) => {
                    write!(w, " ")?;
                    if !b {
                        write!(w, "(not ")?
                    }
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    if !b {
                        write!(w, ")")?
                    }
                }

                val::RVal::I(ref i) => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " ")?;
                    int_to_smt!(w, i)?;
                    write!(w, ")")?
                }

                val::RVal::R(ref r) => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " ")?;
                    rat_to_smt!(w, r)?;
                    write!(w, ")")?
                }

                val::RVal::Array { .. } | val::RVal::DTypNew { .. } => {
                    write!(w, " (= ")?;
                    arg.write(w, |w, v| w.write_all(v.default_str().as_bytes()))?;
                    write!(w, " {})", val)?
                }

                val::RVal::N(_) => (),
            }
        }

        if skipped == self.args.len() {
            write!(w, " true")?
        }
        write!(w, ")")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>//
// base32.rs - base32 implementation
//
// The Base32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A             9 J            18 S            27 3
//     1 B            10 K            19 T            28 4
//     2 C            11 L            20 U            29 5
//     3 D            12 M            21 V            30 6
//     4 E            13 N            22 W            31 7
//     5 F            14 O            23 X
//     6 G            15 P            24 Y         (pad) =
//     7 H            16 Q            25 Z
//     8 I            17 R            26 2
//
// The "Extended Hex" Base 32 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 0             9 9            18 I            27 R
//     1 1            10 A            19 J            28 S
//     2 2            11 B            20 K            29 T
//     3 3            12 C            21 L            30 U
//     4 4            13 D            22 M            31 V
//     5 5            14 E            23 N
//     6 6            15 F            24 O         (pad) =
//     7 7            16 G            25 P
//     8 8            17 H            26 Q
//

use std;

export base32, mk;

const padd: u8 = 61u8;

iface base32 {
    fn encode(src: [u8]) -> [u8];
    fn decode(src: [u8]) -> [u8];
    fn hex_encode(src: [u8]) -> [u8];
    fn hex_decode(src: [u8]) -> [u8];
}

fn mk() -> base32 {
    type _base32 = {table: [u8], table_hex: [u8]};

    impl of base32 for _base32 {
        fn encode(src: [u8]) -> [u8] {
            b32encode(self.table, src)
        }
        fn hex_encode(src: [u8]) -> [u8] {
            b32encode(self.table_hex, src)
        }
        fn decode(src: [u8]) -> [u8] {
            b32decode(src, b32idx_normal)
        }
        fn hex_decode(src: [u8]) -> [u8] {
            b32decode(src, b32idx_hex)
        }
    }

    let table = vec::to_mut(vec::from_elem(32u, 0u8)), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(50u8, 56u8)  { |j| table[i] = j; i += 1u8; }

    let table_hex = vec::to_mut(vec::from_elem(32u, 0u8)), i = 0u8;
    u8::range(48u8, 58u8)  { |j| table_hex[i] = j; i += 1u8; }
    u8::range(65u8, 87u8)  { |j| table_hex[i] = j; i += 1u8; }

    {table: vec::from_mut(table),
     table_hex: vec::from_mut(table_hex)} as base32
}

fn b32encode(table: [u8], src: [u8]) -> [u8] {
    let srclen = vec::len(src);
    let targ: [mutable u8] = [mutable];
    let input = vec::to_mut(vec::from_elem(5u, 0u8));
    let output = vec::to_mut(vec::from_elem(8u, 0u8));
    let curr = 0u, src_curr = 0u;
    let targlen =
        if srclen % 5u == 0u {
            (srclen / 5u) * 8u
        } else {
            (srclen / 5u + 1u) * 8u
        };
    vec::reserve(targ, targlen);
    unsafe { vec::unsafe::set_len(targ, targlen); }

    while srclen > 4u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        srclen -= 5u; src_curr += 5u;

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;
        output[7] = input[4] & 0x1f_u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = table[output[2]];
        targ[curr + 3u] = table[output[3]];
        targ[curr + 4u] = table[output[4]];
        targ[curr + 5u] = table[output[5]];
        targ[curr + 6u] = table[output[6]];
        targ[curr + 7u] = table[output[7]];
        curr += 8u;
    }

    if srclen != 0u {
        input[0] = 0u8; input[1] = 0u8; input[2] = 0u8;
        input[3] = 0u8; input[4] = 0u8;

        alt srclen {
          1u {input[0] = src[src_curr];}
          2u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];}
          3u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];}
          4u {input[0] = src[src_curr];
              input[1] = src[src_curr + 1u];
              input[2] = src[src_curr + 2u];
              input[3] = src[src_curr + 3u];}
          _ { }
        }

        output[0] = input[0] >> 3u8;
        output[1] = (input[0] & 0x07_u8) << 2u8 | input[1] >> 6u8;
        output[2] = (input[1] & 0x3f_u8) >> 1u8;
        output[3] = (input[1] & 0x01_u8) << 4u8 | input[2] >> 4u8;
        output[4] = (input[2] & 0x0f_u8) << 1u8 | input[3] >> 7u8;
        output[5] = (input[3] & 0x7f_u8) >> 2u8;
        output[6] = (input[3] & 0x03_u8) << 3u8 | input[4] >> 5u8;

        targ[curr + 0u] = table[output[0]];
        targ[curr + 1u] = table[output[1]];
        targ[curr + 2u] = if srclen > 1u { table[output[2]] } else { padd };
        targ[curr + 3u] = if srclen > 1u { table[output[3]] } else { padd };
        targ[curr + 4u] = if srclen > 2u { table[output[4]] } else { padd };
        targ[curr + 5u] = if srclen > 3u { table[output[5]] } else { padd };
        targ[curr + 6u] = if srclen > 3u { table[output[6]] } else { padd };
        targ[curr + 7u] = padd;
    }

    vec::from_mut(targ)
}

fn b32decode(src: [u8], b32idx: native fn(u8) -> u8) -> [u8] {
    let srclen = vec::len(src);

    if srclen % 8u != 0u { fail "malformed base32 string"; }
    if srclen == 0u { ret []; }

    let targ: [mutable u8] = [mutable];
    let input = vec::to_mut(vec::from_elem(8u, 0u8));
    let output = vec::to_mut(vec::from_elem(8u, 0u8));
    let curr = 0u, src_curr = 0u;
    let targlen =
        if src[srclen - 6u] == padd {
            srclen / 8u * 5u - 4u
        } else if src[srclen - 4u] == padd {
            srclen / 8u * 5u - 3u
        } else if src[srclen - 3u] == padd {
            srclen / 8u * 5u - 2u
        } else if src[srclen - 1u] == padd {
            srclen / 8u * 5u - 1u
        } else {
            srclen / 8u * 5u
        };
    vec::reserve(targ, targlen);
    unsafe { vec::unsafe::set_len(targ, targlen); }

    while srclen > 8u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        input[5] = src[src_curr + 5u];
        input[6] = src[src_curr + 6u];
        input[7] = src[src_curr + 7u];
        srclen -= 8u; src_curr += 8u;

        output[0] = b32idx(input[0]);
        output[1] = b32idx(input[1]);
        output[2] = b32idx(input[2]);
        output[3] = b32idx(input[3]);
        output[4] = b32idx(input[4]);
        output[5] = b32idx(input[5]);
        output[6] = b32idx(input[6]);
        output[7] = b32idx(input[7]);

        targ[curr + 0u] = output[0] << 3u8 | output[1] >> 2u8;
        targ[curr + 1u] =
            (output[1] & 0x03_u8) << 6u8 | output[2] << 1u8 | output[3] >> 4u8;
        targ[curr + 2u] = (output[3] & 0x0f_u8) << 4u8 | output[4] >> 1u8;
        targ[curr + 3u] =
            (output[4] & 0x01_u8) << 7u8 | output[5] << 2u8 | output[6] >> 3u8;
        targ[curr + 4u] = (output[6] & 0x07_u8) << 5u8 | output[7];
        curr += 5u;
    }

    if srclen == 8u {
        input[0] = src[src_curr];
        input[1] = src[src_curr + 1u];
        input[2] = src[src_curr + 2u];
        input[3] = src[src_curr + 3u];
        input[4] = src[src_curr + 4u];
        input[5] = src[src_curr + 5u];
        input[6] = src[src_curr + 6u];
        input[7] = src[src_curr + 7u];

        output[0] = b32idx(input[0]);
        output[1] = b32idx(input[1]);

        targ[curr + 0u] = output[0] << 3u8 | output[1] >> 2u8;
        if input[2] == padd { ret vec::from_mut(targ); }

        output[2] = b32idx(input[2]);
        output[3] = b32idx(input[3]);

        targ[curr + 1u] =
            (output[1] & 0x03_u8) << 6u8 | output[2] << 1u8 | output[3] >> 4u8;
        if input[4] == padd { ret vec::from_mut(targ); }

        output[4] = b32idx(input[4]);

        targ[curr + 2u] = (output[3] & 0x0f_u8) << 4u8 | output[4] >> 1u8;
        if input[5] == padd { ret vec::from_mut(targ); }

        output[5] = b32idx(input[5]);
        output[6] = b32idx(input[6]);

        targ[curr + 3u] =
            (output[4] & 0x01_u8) << 7u8 | output[5] << 2u8 | output[6] >> 3u8;
        if input[7] == padd { ret vec::from_mut(targ); }

        output[7] = b32idx(input[7]);

        targ[curr + 4u] = (output[6] & 0x07_u8) << 5u8 | output[7];
    }

    vec::from_mut(targ)
}

fn b32idx_normal(x: u8) -> u8 {
    if 65u8 <= x && x <= 90u8 { x - 65u8 }
    else if 50u8 <= x && x <= 56u8 { x - 50u8 + 26u8 }
    else { fail "malformed base32 string"; }
}

fn b32idx_hex(x: u8) -> u8 {
    if 48u8 <= x && x <= 57u8 { x - 48u8 }
    else if 65u8 <= x && x <= 90u8 { x - 65u8 + 10u8 }
    else { fail "malformed base32(hex) string"; }
}

mod tests {
    import std::map;
    import std::map::hashmap;
    import core::str::{bytes, from_bytes};
    enum mode {
        t_encode,
        t_decode,
        t_hex_encode,
        t_hex_decode,
    }
    fn setup(t: mode) -> map::hashmap<str, str> {
        let m = map::new_str_hash::<str>();
        alt t {
          t_decode {
            m.insert("MZXW6YTBOI======", "foobar");
            m.insert("MZXW6YTB", "fooba");
            m.insert("MZXW6YQ=", "foob");
            m.insert("MZXW6===", "foo");
            m.insert("MZXQ====", "fo");
            m.insert("MY======", "f");
          }
          t_encode {
            m.insert("foobar", "MZXW6YTBOI======");
            m.insert("fooba", "MZXW6YTB");
            m.insert("foob",  "MZXW6YQ=");
            m.insert("foo",   "MZXW6===");
            m.insert("fo",    "MZXQ====");
            m.insert("f",     "MY======");
          }
          t_hex_decode {
            m.insert("CPNMUOJ1E8======", "foobar");
            m.insert("CPNMUOJ1", "fooba");
            m.insert("CPNMUOG=", "foob");
            m.insert("CPNMU===", "foo");
            m.insert("CPNG====", "fo");
            m.insert("CO======", "f");
          }
          t_hex_encode {
            m.insert("foobar", "CPNMUOJ1E8======");
            m.insert("fooba", "CPNMUOJ1");
            m.insert("foob",  "CPNMUOG=");
            m.insert("foo",   "CPNMU===");
            m.insert("fo",    "CPNG====");
            m.insert("f",     "CO======");
          }
        }
        m.insert("", "");
        m
    }
    fn do_test(t: mode) {
        let b32 = mk();
        let m = setup(t);
        m.keys { |k|
            let expected = m.get(k);
            let actual = alt t {
              t_decode { from_bytes(b32.decode(bytes(k))) }
              t_encode { from_bytes(b32.encode(bytes(k))) }
              t_hex_decode { from_bytes(b32.hex_decode(bytes(k))) }
              t_hex_encode { from_bytes(b32.hex_encode(bytes(k))) }
            };
            #debug("expected: %s", expected);
            #debug("actual:   %s", actual);
            assert expected == actual;
        }
    }
    #[test]
    fn encode() { do_test(t_encode); }
    #[test]
    fn hex_encode() { do_test(t_hex_encode); }
    #[test]
    fn decode() { do_test(t_decode); }
    #[test]
    fn hex_decode() { do_test(t_hex_decode); }
}
<commit_msg>byebye old one<commit_after><|endoftext|>


<commit_before>//! Module for the card game, after auctions are complete.

use super::pos;
use super::cards;
use super::trick;
use super::bid;
use super::points;

// GameState describes the state of a coinche game, ready to play a card.
pub struct GameState {
    players: [cards::Hand; 4],

    current: pos::PlayerPos,

    contract: bid::Contract,

    scores: [i32; 2],
    tricks: Vec<trick::Trick>,
}

pub fn new_game(first: pos::PlayerPos, hands: [cards::Hand; 4], contract: bid::Contract) -> GameState {
    // Create a new game, deal cards to each player
    GameState {
        players: hands,
        current: first,
        contract: contract,
        tricks: vec![trick::empty_trick(first)],
        scores: [0; 2],
    }
}

#[derive(PartialEq,Debug)]
pub enum GameResult {
    Nothing,
    GameOver([i32;2], pos::Team, [i32;2]),
}

#[derive(PartialEq,Debug)]
pub enum TrickResult {
    Nothing,
    TrickOver(pos::PlayerPos,GameResult),
}

#[derive(PartialEq,Debug)]
pub enum PlayError {
    TurnError,
    CardMissing,
    IncorrectSuit,
    InvalidPiss,
    NonRaisedTrump,
}

impl GameState {

    pub fn play_card(&mut self, player: pos::PlayerPos, card: cards::Card)
                     -> Result<TrickResult,PlayError> {
        if self.current != player {
            return Err(PlayError::TurnError);
        }

        // Is that a valid move?
        try!(self.can_play(player, card));

        // Play the card
        let trump = self.contract.trump;
        let trick_over = self.current_trick_mut().play_card(player, card, trump);

        // Is the trick over?
        let result = if trick_over {
            let winner = self.current_trick().winner;
            let score = self.current_trick().score(trump);
            self.scores[winner.team().0] += score;
            self.tricks.push(trick::empty_trick(winner));
            TrickResult::TrickOver(winner, self.get_game_result())
        } else {
            TrickResult::Nothing
        };

        // Next!
        self.current = self.current.next();

        Ok(result)
    }

    fn get_game_result(&self) -> GameResult {
        if !self.is_over() {
            return GameResult::Nothing;
        }

        let taking_team = self.contract.author.team();
        let taking_score = self.scores[taking_team.0];

        let capot = self.is_capot(taking_team);

        let victory = self.contract.target.victory(taking_score, capot);

        let winners = if victory { taking_team } else { taking_team.opponent() };

        // TODO: Allow for variants in scoring. (See wikipedia article)
        let mut final_scores = [0; 2];
        if victory {
            final_scores[winners.0] = self.contract.target.score();
        } else {
            final_scores[winners.0] = 160;
        }

        GameResult::GameOver(self.scores, winners, final_scores)
    }

    fn is_capot(&self, team: pos::Team) -> bool {
        for trick in self.tricks.iter() {
            if trick.winner.team() != team {
                return false;
            }
        }

        true
    }

    pub fn can_play(&self, p: pos::PlayerPos, card: cards::Card) -> Result<(),PlayError> {
        let hand = self.players[p.0];

        // First, we need the card to be able to play
        if !hand.has(card) {
            return Err(PlayError::CardMissing);;
        }

        if p == self.current_trick().first {
            return Ok(());
        }

        let card_suit = card.suit();
        let starting_suit = self.current_trick().cards[self.current_trick().first.0].suit();
        if card_suit != starting_suit {
            if hand.has_any(starting_suit) {
                return Err(PlayError::IncorrectSuit);
            }

            if card_suit != self.contract.trump {
                let partner_winning = p.is_partner(self.current_trick().winner);
                if !partner_winning && hand.has_any(self.contract.trump) {
                    return Err(PlayError::InvalidPiss);
                }
            }
        }

        // One must raise when playing trump
        if card_suit == self.contract.trump {
            let highest = highest_trump(&self.current_trick(), self.contract.trump, p);
            if points::trump_strength(card.rank()) < highest {
                if has_higher(hand, card_suit, highest) {
                    return Err(PlayError::NonRaisedTrump);;
                }
            }
        }

        Ok(())
    }

    fn is_over(&self) -> bool {
        self.tricks.len() == 8
    }

    fn current_trick(&self) -> &trick::Trick {
        let i = self.tricks.len()-1;
        &self.tricks[i]
    }

    fn current_trick_mut(&mut self) -> &mut trick::Trick {
        let i = self.tricks.len()-1;
        &mut self.tricks[i]
    }
}

#[test]
fn test_play_card() {
    let mut hands = [cards::new_hand(); 4];
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_8));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_X));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_A));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_9));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_7));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_8));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_9));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_J));

    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_Q));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_K));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_X));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_A));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_7));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_8));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_9));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_J));

    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_7));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_8));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_9));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_J));
    hands[2].add(cards::make_card(cards::SPADE, cards::RANK_Q));
    hands[2].add(cards::make_card(cards::SPADE, cards::RANK_K));
    hands[2].add(cards::make_card(cards::HEART, cards::RANK_Q));
    hands[2].add(cards::make_card(cards::HEART, cards::RANK_K));

    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_Q));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_K));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_X));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_A));
    hands[3].add(cards::make_card(cards::SPADE, cards::RANK_X));
    hands[3].add(cards::make_card(cards::SPADE, cards::RANK_A));
    hands[3].add(cards::make_card(cards::HEART, cards::RANK_7));
    hands[3].add(cards::make_card(cards::HEART, cards::RANK_J));

    let contract = bid::Contract {
        trump: cards::HEART,
        author: pos::P0,
        target: bid::Target::Contract80,
        coinche_level: 0,
    };

    let mut game = new_game(pos::P0, hands, contract);

    // Wrong turn
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::CLUB, cards::RANK_X)).err(),
        Some(PlayError::TurnError));
    assert_eq!(
        game.play_card(pos::P0, cards::make_card(cards::CLUB, cards::RANK_7)).ok(),
        Some(TrickResult::Nothing));
    // Card missing
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::HEART, cards::RANK_7)).err(),
        Some(PlayError::CardMissing));
    // Wrong color
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::SPADE, cards::RANK_7)).err(),
        Some(PlayError::IncorrectSuit));
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::CLUB, cards::RANK_Q)).ok(),
        Some(TrickResult::Nothing));
    // Invalid piss
    assert_eq!(
        game.play_card(pos::P2, cards::make_card(cards::DIAMOND, cards::RANK_7)).err(),
        Some(PlayError::InvalidPiss));
    assert_eq!(
        game.play_card(pos::P2, cards::make_card(cards::HEART, cards::RANK_Q)).ok(),
        Some(TrickResult::Nothing));
    // UnderTrump
    assert_eq!(
        game.play_card(pos::P3, cards::make_card(cards::HEART, cards::RANK_7)).err(),
        Some(PlayError::NonRaisedTrump));
    assert_eq!(
        game.play_card(pos::P3, cards::make_card(cards::HEART, cards::RANK_J)).ok(),
        Some(TrickResult::TrickOver(pos::P3)));
}

fn has_higher(hand: cards::Hand, trump: cards::Suit, strength: i32) -> bool {
    for ri in 0..8 {
        let rank = cards::get_rank(ri);
        if points::trump_strength(rank) > strength && hand.has(cards::make_card(trump, rank)) {
            return true
        }
    }

    false
}

#[test]
fn test_has_higher_1() {
    // Simple case: X is always higher than Q.
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_Q)));
}

#[test]
fn test_has_higher_2() {
    // Test that we don't mix colors
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(!has_higher(hand, cards::HEART, points::trump_strength(cards::RANK_Q)));
}

#[test]
fn test_has_higher_3() {
    // In the trump order, X is lower than 9
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_J));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(!has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_9)));
}

#[test]
fn test_has_higher_4() {
    // In the trump order, J is higher than A
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_J));
    assert!(has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_A)));
}

#[test]
fn test_has_higher_5() {
    // Test when we have no trump at all
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_J));
    hand.add(cards::make_card(cards::DIAMOND, cards::RANK_J));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_J));
    assert!(!has_higher(hand, cards::CLUB, points::trump_strength(cards::RANK_7)));
}

fn highest_trump(trick: &trick::Trick, trump: cards::Suit, player: pos::PlayerPos) -> i32 {
    let mut highest = -1;

    for p in trick.first.until(player) {
        if trick.cards[p.0].suit() == trump {
            let str = points::trump_strength(trick.cards[p.0].rank());
            if str > highest {
                highest = str;
            }
        }
    }

    highest
}
<commit_msg>Added 10 de der<commit_after>//! Module for the card game, after auctions are complete.

use super::pos;
use super::cards;
use super::trick;
use super::bid;
use super::points;

// GameState describes the state of a coinche game, ready to play a card.
pub struct GameState {
    players: [cards::Hand; 4],

    current: pos::PlayerPos,

    contract: bid::Contract,

    scores: [i32; 2],
    tricks: Vec<trick::Trick>,
}

pub fn new_game(first: pos::PlayerPos, hands: [cards::Hand; 4], contract: bid::Contract) -> GameState {
    // Create a new game, deal cards to each player
    GameState {
        players: hands,
        current: first,
        contract: contract,
        tricks: vec![trick::empty_trick(first)],
        scores: [0; 2],
    }
}

#[derive(PartialEq,Debug)]
pub enum GameResult {
    Nothing,
    GameOver([i32;2], pos::Team, [i32;2]),
}

#[derive(PartialEq,Debug)]
pub enum TrickResult {
    Nothing,
    TrickOver(pos::PlayerPos,GameResult),
}

#[derive(PartialEq,Debug)]
pub enum PlayError {
    TurnError,
    CardMissing,
    IncorrectSuit,
    InvalidPiss,
    NonRaisedTrump,
}

impl GameState {

    pub fn play_card(&mut self, player: pos::PlayerPos, card: cards::Card)
                     -> Result<TrickResult,PlayError> {
        if self.current != player {
            return Err(PlayError::TurnError);
        }

        // Is that a valid move?
        try!(self.can_play(player, card));

        // Play the card
        let trump = self.contract.trump;
        let trick_over = self.current_trick_mut().play_card(player, card, trump);

        // Is the trick over?
        let result = if trick_over {
            let winner = self.current_trick().winner;
            let score = self.current_trick().score(trump);
            self.scores[winner.team().0] += score;
            if self.tricks.len() == 8 {
                // 10 de der
                self.scores[winner.team().0] += 10;
            } else {
                self.tricks.push(trick::empty_trick(winner));
            }
            TrickResult::TrickOver(winner, self.get_game_result())
        } else {
            TrickResult::Nothing
        };

        // Next!
        self.current = self.current.next();

        Ok(result)
    }

    fn get_game_result(&self) -> GameResult {
        if !self.is_over() {
            return GameResult::Nothing;
        }

        let taking_team = self.contract.author.team();
        let taking_score = self.scores[taking_team.0];

        let capot = self.is_capot(taking_team);

        let victory = self.contract.target.victory(taking_score, capot);

        let winners = if victory { taking_team } else { taking_team.opponent() };

        // TODO: Allow for variants in scoring. (See wikipedia article)
        let mut final_scores = [0; 2];
        if victory {
            final_scores[winners.0] = self.contract.target.score();
        } else {
            final_scores[winners.0] = 160;
        }

        GameResult::GameOver(self.scores, winners, final_scores)
    }

    fn is_capot(&self, team: pos::Team) -> bool {
        for trick in self.tricks.iter() {
            if trick.winner.team() != team {
                return false;
            }
        }

        true
    }

    pub fn can_play(&self, p: pos::PlayerPos, card: cards::Card) -> Result<(),PlayError> {
        let hand = self.players[p.0];

        // First, we need the card to be able to play
        if !hand.has(card) {
            return Err(PlayError::CardMissing);;
        }

        if p == self.current_trick().first {
            return Ok(());
        }

        let card_suit = card.suit();
        let starting_suit = self.current_trick().cards[self.current_trick().first.0].suit();
        if card_suit != starting_suit {
            if hand.has_any(starting_suit) {
                return Err(PlayError::IncorrectSuit);
            }

            if card_suit != self.contract.trump {
                let partner_winning = p.is_partner(self.current_trick().winner);
                if !partner_winning && hand.has_any(self.contract.trump) {
                    return Err(PlayError::InvalidPiss);
                }
            }
        }

        // One must raise when playing trump
        if card_suit == self.contract.trump {
            let highest = highest_trump(&self.current_trick(), self.contract.trump, p);
            if points::trump_strength(card.rank()) < highest {
                if has_higher(hand, card_suit, highest) {
                    return Err(PlayError::NonRaisedTrump);;
                }
            }
        }

        Ok(())
    }

    fn is_over(&self) -> bool {
        self.tricks.len() == 8
    }

    fn current_trick(&self) -> &trick::Trick {
        let i = self.tricks.len()-1;
        &self.tricks[i]
    }

    fn current_trick_mut(&mut self) -> &mut trick::Trick {
        let i = self.tricks.len()-1;
        &mut self.tricks[i]
    }
}

#[test]
fn test_play_card() {
    let mut hands = [cards::new_hand(); 4];
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_8));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_X));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_A));
    hands[0].add(cards::make_card(cards::HEART, cards::RANK_9));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_7));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_8));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_9));
    hands[0].add(cards::make_card(cards::CLUB, cards::RANK_J));

    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_Q));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_K));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_X));
    hands[1].add(cards::make_card(cards::CLUB, cards::RANK_A));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_7));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_8));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_9));
    hands[1].add(cards::make_card(cards::SPADE, cards::RANK_J));

    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_7));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_8));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_9));
    hands[2].add(cards::make_card(cards::DIAMOND, cards::RANK_J));
    hands[2].add(cards::make_card(cards::SPADE, cards::RANK_Q));
    hands[2].add(cards::make_card(cards::SPADE, cards::RANK_K));
    hands[2].add(cards::make_card(cards::HEART, cards::RANK_Q));
    hands[2].add(cards::make_card(cards::HEART, cards::RANK_K));

    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_Q));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_K));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_X));
    hands[3].add(cards::make_card(cards::DIAMOND, cards::RANK_A));
    hands[3].add(cards::make_card(cards::SPADE, cards::RANK_X));
    hands[3].add(cards::make_card(cards::SPADE, cards::RANK_A));
    hands[3].add(cards::make_card(cards::HEART, cards::RANK_7));
    hands[3].add(cards::make_card(cards::HEART, cards::RANK_J));

    let contract = bid::Contract {
        trump: cards::HEART,
        author: pos::P0,
        target: bid::Target::Contract80,
        coinche_level: 0,
    };

    let mut game = new_game(pos::P0, hands, contract);

    // Wrong turn
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::CLUB, cards::RANK_X)).err(),
        Some(PlayError::TurnError));
    assert_eq!(
        game.play_card(pos::P0, cards::make_card(cards::CLUB, cards::RANK_7)).ok(),
        Some(TrickResult::Nothing));
    // Card missing
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::HEART, cards::RANK_7)).err(),
        Some(PlayError::CardMissing));
    // Wrong color
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::SPADE, cards::RANK_7)).err(),
        Some(PlayError::IncorrectSuit));
    assert_eq!(
        game.play_card(pos::P1, cards::make_card(cards::CLUB, cards::RANK_Q)).ok(),
        Some(TrickResult::Nothing));
    // Invalid piss
    assert_eq!(
        game.play_card(pos::P2, cards::make_card(cards::DIAMOND, cards::RANK_7)).err(),
        Some(PlayError::InvalidPiss));
    assert_eq!(
        game.play_card(pos::P2, cards::make_card(cards::HEART, cards::RANK_Q)).ok(),
        Some(TrickResult::Nothing));
    // UnderTrump
    assert_eq!(
        game.play_card(pos::P3, cards::make_card(cards::HEART, cards::RANK_7)).err(),
        Some(PlayError::NonRaisedTrump));
    assert_eq!(
        game.play_card(pos::P3, cards::make_card(cards::HEART, cards::RANK_J)).ok(),
        Some(TrickResult::TrickOver(pos::P3)));
}

fn has_higher(hand: cards::Hand, trump: cards::Suit, strength: i32) -> bool {
    for ri in 0..8 {
        let rank = cards::get_rank(ri);
        if points::trump_strength(rank) > strength && hand.has(cards::make_card(trump, rank)) {
            return true
        }
    }

    false
}

#[test]
fn test_has_higher_1() {
    // Simple case: X is always higher than Q.
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_Q)));
}

#[test]
fn test_has_higher_2() {
    // Test that we don't mix colors
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(!has_higher(hand, cards::HEART, points::trump_strength(cards::RANK_Q)));
}

#[test]
fn test_has_higher_3() {
    // In the trump order, X is lower than 9
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_J));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_X));
    assert!(!has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_9)));
}

#[test]
fn test_has_higher_4() {
    // In the trump order, J is higher than A
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_8));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_J));
    assert!(has_higher(hand, cards::SPADE, points::trump_strength(cards::RANK_A)));
}

#[test]
fn test_has_higher_5() {
    // Test when we have no trump at all
    let mut hand = cards::new_hand();

    hand.add(cards::make_card(cards::HEART, cards::RANK_J));
    hand.add(cards::make_card(cards::DIAMOND, cards::RANK_J));
    hand.add(cards::make_card(cards::SPADE, cards::RANK_J));
    assert!(!has_higher(hand, cards::CLUB, points::trump_strength(cards::RANK_7)));
}

fn highest_trump(trick: &trick::Trick, trump: cards::Suit, player: pos::PlayerPos) -> i32 {
    let mut highest = -1;

    for p in trick.first.until(player) {
        if trick.cards[p.0].suit() == trump {
            let str = points::trump_strength(trick.cards[p.0].rank());
            if str > highest {
                highest = str;
            }
        }
    }

    highest
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Clone, Copy)]
pub struct Timestamp {
    pub nano: u64,
    pub us: u64,
    pub ms: u64,
    pub s: u64,
    pub m: u64,
    pub h: u64,
}

impl Timestamp {
    pub fn format(nano_total: u64) -> String {
        let us_total = nano_total / 1_000;
        let ms_total = us_total / 1_000;
        let s_total = ms_total / 1_000;
        let m_total = s_total / 60;
        let h = m_total / 60;

        if h == 0 {
            format!("{:02}:{:02}.{:03}",
                m_total % 60, s_total % 1_000, ms_total % 1_000
            ).to_owned()
        } else {
            format!("{:02}:{:02}:{:02}.{:03}",
                h, m_total % 60, s_total % 1_000, ms_total % 1_000
            ).to_owned()
        }
    }

    pub fn from_nano(nano_total: u64) -> Self {
        let us_total = nano_total / 1_000;
        let ms_total = us_total / 1_000;
        let s_total = ms_total / 1_000;
        let m_total = s_total / 60;

        Timestamp {
            nano: nano_total % 1_000,
            us: us_total % 1_000,
            ms: ms_total % 1_000,
            s: s_total % 1_000,
            m: m_total % 60,
            h: m_total / 60,
        }
    }

    pub fn from_signed_nano(nano: i64) -> Self {
        if nano.is_negative() {
            Timestamp {
                nano: 0,
                us: 0,
                ms: 0,
                s: 0,
                m: 0,
                h: 0,
            }
        } else {
            Timestamp::from_nano(nano as u64)
        }
    }
}

impl fmt::Display for Timestamp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let prefix = if self.h > 0 {
            format!("{:02}:", self.h).to_owned()
        }
        else {
            String::new()
        };

        write!(f, "{}{:02}:{:02}.{:03}",
            prefix, self.m, self.s, self.ms
        )
    }
}
<commit_msg>Fix seconds display (#25)<commit_after>use std::fmt;

#[derive(Clone, Copy)]
pub struct Timestamp {
    pub nano: u64,
    pub us: u64,
    pub ms: u64,
    pub s: u64,
    pub m: u64,
    pub h: u64,
}

impl Timestamp {
    pub fn format(nano_total: u64) -> String {
        let us_total = nano_total / 1_000;
        let ms_total = us_total / 1_000;
        let s_total = ms_total / 1_000;
        let m_total = s_total / 60;
        let h = m_total / 60;

        if h == 0 {
            format!("{:02}:{:02}.{:03}",
                m_total % 60, s_total % 60, ms_total % 1_000
            ).to_owned()
        } else {
            format!("{:02}:{:02}:{:02}.{:03}",
                h, m_total % 60, s_total % 60, ms_total % 1_000
            ).to_owned()
        }
    }

    pub fn from_nano(nano_total: u64) -> Self {
        let us_total = nano_total / 1_000;
        let ms_total = us_total / 1_000;
        let s_total = ms_total / 1_000;
        let m_total = s_total / 60;

        Timestamp {
            nano: nano_total % 1_000,
            us: us_total % 1_000,
            ms: ms_total % 1_000,
            s: s_total % 60,
            m: m_total % 60,
            h: m_total / 60,
        }
    }

    pub fn from_signed_nano(nano: i64) -> Self {
        if nano.is_negative() {
            Timestamp {
                nano: 0,
                us: 0,
                ms: 0,
                s: 0,
                m: 0,
                h: 0,
            }
        } else {
            Timestamp::from_nano(nano as u64)
        }
    }
}

impl fmt::Display for Timestamp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let prefix = if self.h > 0 {
            format!("{:02}:", self.h).to_owned()
        }
        else {
            String::new()
        };

        write!(f, "{}{:02}:{:02}.{:03}",
            prefix, self.m, self.s, self.ms
        )
    }
}
<|endoftext|>