<commit_before>use std::cmp;
use fnv::FnvHashMap;
use error::{Error, ErrorKind};
use result::Result;
use utf8::{DOLLAR, DOT};

const ROOT_QUERY_STR_OFFSET: usize = 2;

#[derive(Debug)]
pub struct Query<'a> {
    pub i: usize,
    pub ri: usize,
    pub target: bool,
    pub children: Option<FnvHashMap<&'a [u8], Query<'a>>>,
}

/// A pattern tree associated with the queries
pub struct QueryTree<'a> {
    pub root: FnvHashMap<&'a [u8], Query<'a>>,
    pub num_queries: usize,

    pub level: usize,
    pub qi: usize,
}

impl<'a> QueryTree<'a> {
    pub fn new<S: ?Sized + AsRef<[u8]>>(queries: &[&'a S]) -> Result<Self> {
        let mut root = FnvHashMap::default();
        let mut level = 0;
        let mut qi = 0;

        for (ri, s) in queries.into_iter().map(|s| (*s).as_ref()).enumerate() {
            if !is_valid_query_str(s) {
                return Err(Error::from(ErrorKind::InvalidQuery));
            }

            let (l, next_qi) = set_queries(&mut root, &s[ROOT_QUERY_STR_OFFSET..], qi, ri);
            level = cmp::max(level, l);
            qi = next_qi;
        }

        Ok(Self {
            root,
            num_queries: queries.len(),
            level,
            qi,
        })
    }
}

#[inline]
fn is_valid_query_str(query_str: &[u8]) -> bool {
    if query_str.len() < ROOT_QUERY_STR_OFFSET + 1 || query_str[0] != DOLLAR || query_str[1] != DOT {
        return false;
    }
    let mut s = ROOT_QUERY_STR_OFFSET - 1;
    for i in s + 1..query_str.len() {
        if query_str[i] != DOT {
            continue;
        }
        if i == s + 1 || i == query_str.len() - 1 {
            return false;
        }
        s = i;
    }
    true
}

#[inline]
fn set_queries<'a>(queries: &mut FnvHashMap<&'a [u8], Query<'a>>, s: &'a [u8], qi: usize, ri: usize) -> (usize, usize) {
    for j in 0..s.len() {
        if s[j] == DOT {
            let (t, u) = s.split_at(j);
            let query = queries.entry(t).or_insert(Query {
                i: qi,
                ri: ri,
                target: false,
                children: None,
            });
            let mut children = query.children.get_or_insert(FnvHashMap::default());
            let (child_level, next_qi) = set_queries(
                &mut children,
                &u[1..],
                if qi == query.i { qi + 1 } else { qi },
                ri,
            );
            return (child_level + 1, next_qi);
        }
    }

    if !queries.contains_key(s) {
        queries.insert(
            s,
            Query {
                i: qi,
                ri: ri,
                target: true,
                children: None,
            },
        );
        (1, qi + 1)
    } else {
        queries.get_mut(s).unwrap().target = true;
        (1, qi)
    }
}

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

    #[test]
    fn test_is_valid_query_str() {
        struct TestCase<'a> {
            query_str: &'a str,
            want: bool,
        }
        let test_cases = vec![
            TestCase {
                query_str: "",
                want: false,
            },
            TestCase {
                query_str: "$",
                want: false,
            },
            TestCase {
                query_str: "$.",
                want: false,
            },
            TestCase {
                query_str: "$..",
                want: false,
            },
            TestCase {
                query_str: "a.a",
                want: false,
            },
            TestCase {
                query_str: "$aa",
                want: false,
            },
            TestCase {
                query_str: "$.a",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.",
                want: false,
            },
            TestCase {
                query_str: "$.aaaa.b",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.bbbb",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.bbbb.",
                want: false,
            },
        ];
        for t in test_cases {
            let got = is_valid_query_str(t.query_str.as_bytes());
            assert_eq!(t.want, got);
        }
    }
}
<commit_msg>refactor(set_queries): take the mutable reference of `qi`<commit_after>use std::cmp;
use fnv::FnvHashMap;
use error::{Error, ErrorKind};
use result::Result;
use utf8::{DOLLAR, DOT};

const ROOT_QUERY_STR_OFFSET: usize = 2;

#[derive(Debug)]
pub struct Query<'a> {
    pub i: usize,
    pub ri: usize,
    pub target: bool,
    pub children: Option<FnvHashMap<&'a [u8], Query<'a>>>,
}

/// A pattern tree associated with the queries
pub struct QueryTree<'a> {
    pub root: FnvHashMap<&'a [u8], Query<'a>>,
    pub num_queries: usize,

    pub level: usize,
    pub qi: usize,
}

impl<'a> QueryTree<'a> {
    pub fn new<S: ?Sized + AsRef<[u8]>>(queries: &[&'a S]) -> Result<Self> {
        let mut root = FnvHashMap::default();
        let mut level = 0;
        let mut qi = 0;

        for (ri, s) in queries.into_iter().map(|s| (*s).as_ref()).enumerate() {
            if !is_valid_query_str(s) {
                return Err(Error::from(ErrorKind::InvalidQuery));
            }

            let l = set_queries(&mut root, &s[ROOT_QUERY_STR_OFFSET..], &mut qi, ri);
            level = cmp::max(level, l);
        }

        Ok(Self {
            root,
            num_queries: queries.len(),
            level,
            qi,
        })
    }
}

#[inline]
fn is_valid_query_str(query_str: &[u8]) -> bool {
    if query_str.len() < ROOT_QUERY_STR_OFFSET + 1 || query_str[0] != DOLLAR || query_str[1] != DOT {
        return false;
    }
    let mut s = ROOT_QUERY_STR_OFFSET - 1;
    for i in s + 1..query_str.len() {
        if query_str[i] != DOT {
            continue;
        }
        if i == s + 1 || i == query_str.len() - 1 {
            return false;
        }
        s = i;
    }
    true
}

#[inline]
fn set_queries<'a>(queries: &mut FnvHashMap<&'a [u8], Query<'a>>, s: &'a [u8], qi: &mut usize, ri: usize) -> usize {
    for j in 0..s.len() {
        if s[j] == DOT {
            let (t, u) = s.split_at(j);
            let query = queries.entry(t).or_insert_with(|| {
                let query = Query {
                    i: *qi,
                    ri: ri,
                    target: false,
                    children: None,
                };
                *qi += 1;
                query
            });
            let mut children = query.children.get_or_insert(FnvHashMap::default());
            return set_queries(&mut children, &u[1..], qi, ri) + 1;
        }
    }

    if !queries.contains_key(s) {
        queries.insert(
            s,
            Query {
                i: *qi,
                ri: ri,
                target: false,
                children: None,
            },
        );
        *qi += 1;
    }
    queries.get_mut(s).unwrap().target = true;
    1
}

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

    #[test]
    fn test_is_valid_query_str() {
        struct TestCase<'a> {
            query_str: &'a str,
            want: bool,
        }
        let test_cases = vec![
            TestCase {
                query_str: "",
                want: false,
            },
            TestCase {
                query_str: "$",
                want: false,
            },
            TestCase {
                query_str: "$.",
                want: false,
            },
            TestCase {
                query_str: "$..",
                want: false,
            },
            TestCase {
                query_str: "a.a",
                want: false,
            },
            TestCase {
                query_str: "$aa",
                want: false,
            },
            TestCase {
                query_str: "$.a",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.",
                want: false,
            },
            TestCase {
                query_str: "$.aaaa.b",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.bbbb",
                want: true,
            },
            TestCase {
                query_str: "$.aaaa.bbbb.",
                want: false,
            },
        ];
        for t in test_cases {
            let got = is_valid_query_str(t.query_str.as_bytes());
            assert_eq!(t.want, got);
        }
    }
}
<|endoftext|>


<commit_before>//! Implements a command for sending events to Sentry.
use clap::{App, Arg, ArgMatches};
use itertools::Itertools;
use serde_json::Value;

use prelude::*;
use config::Config;
use event::{Event, Message};
use api::Api;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("Send a manual event to Sentry.")
        .arg(Arg::with_name("level")
            .value_name("LEVEL")
            .long("level")
            .short("l")
            .help("Optional event severity/log level. [defaults to 'error']"))
        .arg(Arg::with_name("release")
            .value_name("RELEASE")
            .long("release")
            .short("r")
            .help("Optional identifier of the release."))
        .arg(Arg::with_name("dist")
            .value_name("DISTRIBUTION")
            .long("dist")
            .short("d")
            .help("Set the distribution."))
        .arg(Arg::with_name("environment")
            .value_name("ENVIRONMENT")
            .long("env")
            .short("E")
            .help("Send with a specific environment."))
        .arg(Arg::with_name("no_environ")
             .long("no-environ")
             .help("Do not send environment variables along"))
        .arg(Arg::with_name("message")
            .value_name("MESSAGE")
            .long("message")
            .short("m")
            .multiple(true)
            .number_of_values(1)
            .help("The event message."))
        .arg(Arg::with_name("message_args")
            .value_name("MESSAGE_ARG")
            .long("message-arg")
            .short("a")
            .multiple(true)
            .number_of_values(1)
            .help("Arguments for the event message."))
        .arg(Arg::with_name("platform")
            .value_name("PLATFORM")
            .long("platform")
            .short("p")
            .help("Override the default 'other' platform specifier."))
        .arg(Arg::with_name("tags")
            .value_name("KEY:VALUE")
            .long("tag")
            .short("t")
            .multiple(true)
            .number_of_values(1)
            .help("Add a tag (key:value) to the event."))
        .arg(Arg::with_name("extra")
            .value_name("KEY:VALUE")
            .long("extra")
            .short("e")
            .multiple(true)
            .number_of_values(1)
            .help("Add extra information (key:value) to the event."))
        .arg(Arg::with_name("user_data")
             .value_name("KEY:VALUE")
             .long("user")
             .short("u")
            .multiple(true)
            .number_of_values(1)
            .help("Add user information (key:value) to the event. \
                   [eg: id:42, username:foo]"))
        .arg(Arg::with_name("fingerprint")
            .value_name("FINGERPRINT")
            .long("fingerprint")
            .short("f")
            .multiple(true)
            .number_of_values(1)
            .help("Change the fingerprint of the event."))
        .arg(Arg::with_name("logfile")
            .value_name("PATH")
            .long("logfile")
            .help("Send a logfile as breadcrumbs with the event (last 100 records)"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let mut event = Event::new_prefilled()?;
    event.level = matches.value_of("level").unwrap_or("error").into();
    if let Some(release) = matches.value_of("release") {
        event.release = Some(release.into());
    } else {
        event.detect_release();
    }
    event.dist = matches.value_of("dist").map(|x| x.into());
    event.platform = matches.value_of("platform").unwrap_or("other").into();
    event.environment = matches.value_of("environment").map(|x| x.into());

    if let Some(mut lines) = matches.values_of("message") {
        event.message = Some(Message {
            message: lines.join("\n"),
            params: if let Some(args) = matches.values_of("message_args") {
                args.map(|x| x.to_string()).collect()
            } else {
                vec![]
            },
        });
    }

    if let Some(tags) = matches.values_of("tags") {
        for tag in tags {
            let mut split = tag.splitn(2, ':');
            let key = split.next().ok_or("missing tag key")?;
            let value = split.next().ok_or("missing tag value")?;
            event.tags.insert(key.into(), value.into());
        }
    }

    if matches.is_present("no-environ") {
        event.extra.remove("environ");
    }
    if let Some(extra) = matches.values_of("extra") {
        for pair in extra {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing extra key")?;
            let value = split.next().ok_or("missing extra value")?;
            event.extra.insert(key.into(), Value::String(value.into()));
        }
    }

    if let Some(user_data) = matches.values_of("user_data") {
        event.user.remove("username");
        for pair in user_data {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing user key")?;
            let value = split.next().ok_or("missing user value")?;
            event.user.insert(key.into(), value.into());
        }
    }

    if let Some(fingerprint) = matches.values_of("fingerprint") {
        event.fingerprint = Some(fingerprint.map(|x| x.to_string()).collect());
    }

    if let Some(logfile) = matches.value_of("logfile") {
        event.attach_logfile(logfile, false)?;
    }

    let dsn = config.get_dsn()?;

    // handle errors here locally so that we do not get the extra "use sentry-cli
    // login" to sign in which would be in appropriate here.
    match Api::new(config).send_event(&dsn, &event) {
        Ok(event_id) => {
            println!("Event sent: {}", event_id);
        }
        Err(err) => {
            println!("error: could not send event: {}", err);
        }
    };

    Ok(())
}
<commit_msg>fix: Print to stderr and exit(1) when event can't send (#169)<commit_after>//! Implements a command for sending events to Sentry.
use clap::{App, Arg, ArgMatches};
use itertools::Itertools;
use serde_json::Value;

use prelude::*;
use config::Config;
use event::{Event, Message};
use api::Api;

pub fn make_app<'a, 'b: 'a>(app: App<'a, 'b>) -> App<'a, 'b> {
    app.about("Send a manual event to Sentry.")
        .arg(Arg::with_name("level")
            .value_name("LEVEL")
            .long("level")
            .short("l")
            .help("Optional event severity/log level. [defaults to 'error']"))
        .arg(Arg::with_name("release")
            .value_name("RELEASE")
            .long("release")
            .short("r")
            .help("Optional identifier of the release."))
        .arg(Arg::with_name("dist")
            .value_name("DISTRIBUTION")
            .long("dist")
            .short("d")
            .help("Set the distribution."))
        .arg(Arg::with_name("environment")
            .value_name("ENVIRONMENT")
            .long("env")
            .short("E")
            .help("Send with a specific environment."))
        .arg(Arg::with_name("no_environ")
             .long("no-environ")
             .help("Do not send environment variables along"))
        .arg(Arg::with_name("message")
            .value_name("MESSAGE")
            .long("message")
            .short("m")
            .multiple(true)
            .number_of_values(1)
            .help("The event message."))
        .arg(Arg::with_name("message_args")
            .value_name("MESSAGE_ARG")
            .long("message-arg")
            .short("a")
            .multiple(true)
            .number_of_values(1)
            .help("Arguments for the event message."))
        .arg(Arg::with_name("platform")
            .value_name("PLATFORM")
            .long("platform")
            .short("p")
            .help("Override the default 'other' platform specifier."))
        .arg(Arg::with_name("tags")
            .value_name("KEY:VALUE")
            .long("tag")
            .short("t")
            .multiple(true)
            .number_of_values(1)
            .help("Add a tag (key:value) to the event."))
        .arg(Arg::with_name("extra")
            .value_name("KEY:VALUE")
            .long("extra")
            .short("e")
            .multiple(true)
            .number_of_values(1)
            .help("Add extra information (key:value) to the event."))
        .arg(Arg::with_name("user_data")
             .value_name("KEY:VALUE")
             .long("user")
             .short("u")
            .multiple(true)
            .number_of_values(1)
            .help("Add user information (key:value) to the event. \
                   [eg: id:42, username:foo]"))
        .arg(Arg::with_name("fingerprint")
            .value_name("FINGERPRINT")
            .long("fingerprint")
            .short("f")
            .multiple(true)
            .number_of_values(1)
            .help("Change the fingerprint of the event."))
        .arg(Arg::with_name("logfile")
            .value_name("PATH")
            .long("logfile")
            .help("Send a logfile as breadcrumbs with the event (last 100 records)"))
}

pub fn execute<'a>(matches: &ArgMatches<'a>, config: &Config) -> Result<()> {
    let mut event = Event::new_prefilled()?;
    event.level = matches.value_of("level").unwrap_or("error").into();
    if let Some(release) = matches.value_of("release") {
        event.release = Some(release.into());
    } else {
        event.detect_release();
    }
    event.dist = matches.value_of("dist").map(|x| x.into());
    event.platform = matches.value_of("platform").unwrap_or("other").into();
    event.environment = matches.value_of("environment").map(|x| x.into());

    if let Some(mut lines) = matches.values_of("message") {
        event.message = Some(Message {
            message: lines.join("\n"),
            params: if let Some(args) = matches.values_of("message_args") {
                args.map(|x| x.to_string()).collect()
            } else {
                vec![]
            },
        });
    }

    if let Some(tags) = matches.values_of("tags") {
        for tag in tags {
            let mut split = tag.splitn(2, ':');
            let key = split.next().ok_or("missing tag key")?;
            let value = split.next().ok_or("missing tag value")?;
            event.tags.insert(key.into(), value.into());
        }
    }

    if matches.is_present("no-environ") {
        event.extra.remove("environ");
    }
    if let Some(extra) = matches.values_of("extra") {
        for pair in extra {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing extra key")?;
            let value = split.next().ok_or("missing extra value")?;
            event.extra.insert(key.into(), Value::String(value.into()));
        }
    }

    if let Some(user_data) = matches.values_of("user_data") {
        event.user.remove("username");
        for pair in user_data {
            let mut split = pair.splitn(2, ':');
            let key = split.next().ok_or("missing user key")?;
            let value = split.next().ok_or("missing user value")?;
            event.user.insert(key.into(), value.into());
        }
    }

    if let Some(fingerprint) = matches.values_of("fingerprint") {
        event.fingerprint = Some(fingerprint.map(|x| x.to_string()).collect());
    }

    if let Some(logfile) = matches.value_of("logfile") {
        event.attach_logfile(logfile, false)?;
    }

    let dsn = config.get_dsn()?;

    // handle errors here locally so that we do not get the extra "use sentry-cli
    // login" to sign in which would be in appropriate here.
    match Api::new(config).send_event(&dsn, &event) {
        Ok(event_id) => {
            println!("Event sent: {}", event_id);
        }
        Err(err) => {
            println_stderr!("error: could not send event: {}", err);
            return Err(ErrorKind::QuietExit(1).into());
        }
    };

    Ok(())
}
<|endoftext|>


<commit_before>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::size_of;

pub trait OdbcType<'a>: Sized {
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self {
        unreachable!()
    }
    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

impl<'a> OdbcType<'a> for String {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer)
            .unwrap()
            .to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

impl<'a> OdbcType<'a> for &'a str {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer)
            .unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
    where T: Copy
{
    unsafe {
        from_raw_parts(buf.as_ptr() as *const T, 1)[0]
    }
}

impl<'a> OdbcType<'a> for u8 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for i8 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for i16 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for u16 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for i32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for u32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for i64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for u64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for f32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}

impl<'a> OdbcType<'a> for f64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }
}
<commit_msg>a bit more security<commit_after>use ffi;
use std::str::from_utf8;
use std::slice::from_raw_parts;
use std::mem::size_of;

pub trait OdbcType<'a>: Sized {
    fn c_data_type() -> ffi::SqlCDataType;
    fn convert(_: &'a [u8]) -> Self {
        unreachable!()
    }
    fn column_size(&self) -> ffi::SQLULEN { unreachable!() }
    fn value_ptr(&self) -> ffi::SQLPOINTER { unreachable!() }
    fn decimal_digits(&self) -> ffi::SQLSMALLINT {
        0
    }
}

impl<'a> OdbcType<'a> for String {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer)
            .unwrap()
            .to_owned()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

impl<'a> OdbcType<'a> for &'a str {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        from_utf8(buffer)
            .unwrap()
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.as_bytes().len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.as_bytes().as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

fn convert_primitive<T>(buf: &[u8]) -> T
    where T: Copy
{
    unsafe {
        from_raw_parts(buf.as_ptr() as *const T, 1)[0]
    }
}

impl<'a> OdbcType<'a> for u8 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UTINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for i8 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_STINYINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for i16 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SSHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for u16 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_USHORT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for i32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SLONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for u32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_ULONG
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for i64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_SBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for u64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_UBIGINT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for f32 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_FLOAT
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}

impl<'a> OdbcType<'a> for f64 {
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_DOUBLE
    }

    fn convert(buffer: &'a [u8]) -> Self {
        convert_primitive(buffer)
    }

    fn column_size(&self) -> ffi::SQLULEN { size_of::<Self>() as ffi::SQLULEN }
    fn value_ptr(&self) -> ffi::SQLPOINTER { self as *const Self as ffi::SQLPOINTER }
}
<|endoftext|>


<commit_before>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) Nathan Zadoks <nathan@nathan7.eu>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
//! Traits for stacks.

/// A trait for objects that hold ownership of a stack.
pub trait Stack {
  /// Returns the base of the stack.
  /// On all modern architectures, the stack grows downwards,
  /// so this is the highest address.
  fn base(&self) -> *mut u8;
  /// Returns the bottom of the stack.
  /// On all modern architectures, the stack grows downwards,
  /// so this is the lowest address.
  fn limit(&self) -> *mut u8;
}

/// A marker trait for `Stack` objects with a guard page.
///
/// A guarded stack must guarantee that any access of data at addresses `limit()` to
/// `limit().offset(4096)` will abnormally terminate the program.
pub unsafe trait GuardedStack {}
<commit_msg>fix doc comment of Stack::limit<commit_after>// This file is part of libfringe, a low-level green threading library.
// Copyright (c) Nathan Zadoks <nathan@nathan7.eu>
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
//! Traits for stacks.

/// A trait for objects that hold ownership of a stack.
pub trait Stack {
  /// Returns the base of the stack.
  /// On all modern architectures, the stack grows downwards,
  /// so this is the highest address.
  fn base(&self) -> *mut u8;
  /// Returns the limit of the stack.
  /// On all modern architectures, the stack grows downwards,
  /// so this is the lowest address.
  fn limit(&self) -> *mut u8;
}

/// A marker trait for `Stack` objects with a guard page.
///
/// A guarded stack must guarantee that any access of data at addresses `limit()` to
/// `limit().offset(4096)` will abnormally terminate the program.
pub unsafe trait GuardedStack {}
<|endoftext|>


<commit_before>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.

use HashMap = collections::HashMap;

pub type UpdateFunction<T, D> = fn (obj: &mut T, delta: &D);

/// Keeps track of the current state of objects.
/// Also keeps an update function per state.
/// This is because otherwise all states require same logic.
pub struct StateMachine<Object, Delta> {
    current: State<CurrentState<Object>>,
    states: State<State<Object>>,
    update_functions: State<UpdateFunction<Object, Delta>>
}

impl<T, D> StateMachine<T, D> {
    /// Adds a new state.
    pub fn add_state(
            &mut self,
            state_id: uint,
            state: State<T>,
            update: Option<UpdateFunction<T, D>>
    ) {
        self.states.objects.insert(state_id, state);
        match update {
            None => {},
            Some(fun) => { self.update_functions.objects.insert(state_id, fun); }
        }
    }

    /// Adds a new object.
    pub fn add_object(
            &mut self,
            state_id: uint,
            obj_id: uint,
            obj: T) {
        self.current.objects.insert(obj_id, CurrentState { state: state_id });
        self.states.objects.get_mut(&state_id).objects.insert(obj_id, obj);
    }

    /// Returns the current value of object by looking up in correct state.
    #[inline(always)]
    pub fn val<'a>(&'a self, obj: uint) -> &'a T {
        let &CurrentState { state: state } = self.current.objects.get(&obj);
        self.states.objects.get(&state).objects.get(&obj)
    }

    /// Returns the current `state_id` of an object.
    pub fn state_id(&self, obj: uint) -> uint {
        let &CurrentState { state: state } = self.current.objects.get(&obj);
        state
    }
}

/// Stores the current state of an object.
struct CurrentState<Object> {
    state: uint,
}

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for StateMachine<T, D> {
    fn update(&mut self, delta: &D) {
        for (id_state, state) in self.states.objects.mut_iter() {
            match self.update_functions.objects.find(id_state) {
                    None => {},
                    Some(fun) => {
                        for (_, obj) in state.objects.mut_iter() {
                            (*fun)(obj, delta);
                        }
                    }
            }
        }
    }
}

<commit_msg>Added state<commit_after>
//! A different way of thinking about states.
//!
//! All objects are stored in a state.

use HashMap = collections::HashMap;

pub type UpdateFunction<T, D> = fn (obj: &mut T, delta: &D);

/// Keeps track of the current state of objects.
/// Also keeps an update function per state.
/// This is because otherwise all states require same logic.
pub struct StateMachine<Object, Delta> {
    current: State<CurrentState<Object>>,
    states: State<State<Object>>,
    update_functions: State<UpdateFunction<Object, Delta>>
}

impl<T, D> StateMachine<T, D> {
    /// Adds a new state.
    pub fn add_state(
            &mut self,
            state_id: uint,
            state: State<T>,
            update: Option<UpdateFunction<T, D>>
    ) {
        self.states.objects.insert(state_id, state);
        match update {
            None => {},
            Some(fun) => { self.update_functions.objects.insert(state_id, fun); }
        }
    }

    /// Adds a new object.
    pub fn add_object(
            &mut self,
            state_id: uint,
            obj_id: uint,
            obj: T) {
        self.current.objects.insert(obj_id, CurrentState { state: state_id });
        self.states.objects.get_mut(&state_id).objects.insert(obj_id, obj);
    }

    /// Returns the current value of object by looking up in correct state.
    #[inline(always)]
    pub fn val<'a>(&'a self, obj: uint) -> &'a T {
        let &CurrentState { state: state } = self.current.objects.get(&obj);
        self.states.objects.get(&state).objects.get(&obj)
    }

    /// Returns the current `state_id` of an object.
    pub fn state_id(&self, obj: uint) -> uint {
        let &CurrentState { state: state } = self.current.objects.get(&obj);
        state
    }

    /// Returns the current state of an object.
    pub fn state<'a>(&'a self, obj: uint) -> &'a State<T> {
        let &CurrentState { state: state } = self.current.objects.get(&obj);
        self.states.objects.get(&state)
    }
}

/// Stores the current state of an object.
struct CurrentState<Object> {
    state: uint,
}

/// Contains objects.
pub struct State<Object> {
    objects: HashMap<uint, Object>,
}

impl<T> State<T> {
    /// Moves an object from one state to another.
    pub fn move_to(&mut self, to: &mut State<T>, obj: uint) {
        let pop = self.objects.pop(&obj);
        match pop {
            None => {},
            Some(val) => { to.objects.insert(obj, val); }
        }
    }
}

/// Updates on delta information.
///
/// For any type implementing this trait,
/// there is a `State<T>` and `StateMachine<T>`
/// which also implements this trait.
pub trait UpdateDelta<D> {
    /// Updates all the objects with delta information.
    fn update(&mut self, delta: &D);
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for State<T> {
    fn update(&mut self, delta: &D) {
        for (_, obj) in self.objects.mut_iter() {
            obj.update(delta);
        }
    }
}

impl<T: UpdateDelta<D>, D>
UpdateDelta<D> for StateMachine<T, D> {
    fn update(&mut self, delta: &D) {
        for (id_state, state) in self.states.objects.mut_iter() {
            match self.update_functions.objects.find(id_state) {
                    None => {},
                    Some(fun) => {
                        for (_, obj) in state.objects.mut_iter() {
                            (*fun)(obj, delta);
                        }
                    }
            }
        }
    }
}

<|endoftext|>


<commit_before>extern crate rand;

const ROWS: i8 = 9;
const COLS: i8 = 12;
const TILES: i8 = 108;
const PLAYERS: i8 = 4;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Game {
    players: Vec<Player>,
    board: Board,
    turn: PlayerId,
    merge_decision: Option<PlayerId>
}

#[derive(RustcDecodable, RustcEncodable)]
struct Player {
    id: PlayerId,
    money: i32,
    shares: PlayerShares,
    tiles: Vec<Tile>
}

type PlayerId = i8;

#[derive(RustcDecodable, RustcEncodable)]
struct PlayerShares {
    luxor: i8,
    tower: i8,
    american: i8,
    festival: i8,
    worldwide: i8,
    continental: i8,
    imperial: i8
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct Tile { row: i8, col: i8 }

#[derive(RustcDecodable, RustcEncodable)]
struct Board {
    slots: Vec<Vec<Slot>>
}

#[derive(RustcDecodable, RustcEncodable)]
struct Slot {
    hotel: Option<Hotel>
}

#[derive(RustcDecodable, RustcEncodable)]
enum Hotel { Luxor, Tower, American, Festival, Worldwide, Continental, Imperial }

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn choose_tiles(tiles: Vec<Tile>, count: usize) -> Vec<Tile> {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = (rand::random::<i8>() as usize) % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    random_tiles
}

pub fn initial_state() -> Game {
    let slots = (0..COLS)
        .map(|_| (0..ROWS).map(|_| Slot { hotel: None } ).collect() )
        .collect();
    let tiles = (0..TILES).map(|i| Tile { row: i / COLS, col: i % ROWS }).collect();
    let mut chosen_tiles = choose_tiles(tiles, 6*PLAYERS as usize);
    let tiles1 = chosen_tiles.split_off(18);
    let tiles2 = chosen_tiles.split_off(12);
    let tiles3 = chosen_tiles.split_off(6);
    let tiles4 = chosen_tiles;
    let players = vec![
        new_player(1, tiles1),
        new_player(2, tiles2),
        new_player(3, tiles3),
        new_player(4, tiles4)];
    Game {
        board: Board { slots: slots },
        players: players,
        turn: 1,
        merge_decision: None
    }
}
<commit_msg>Add actions<commit_after>extern crate rand;

const ROWS: i8 = 9;
const COLS: i8 = 12;
const TILES: i8 = 108;
const PLAYERS: i8 = 4;

#[derive(RustcDecodable, RustcEncodable)]
pub struct Game {
    players: Vec<Player>,
    board: Board,
    turn: PlayerId,
    merge_decision: Option<PlayerId>
}

#[derive(RustcDecodable, RustcEncodable)]
struct Player {
    id: PlayerId,
    money: i32,
    shares: PlayerShares,
    tiles: Vec<Tile>
}

type PlayerId = i8;

#[derive(RustcDecodable, RustcEncodable)]
struct PlayerShares {
    luxor: i8,
    tower: i8,
    american: i8,
    festival: i8,
    worldwide: i8,
    continental: i8,
    imperial: i8
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
struct Tile { row: i8, col: i8 }

#[derive(RustcDecodable, RustcEncodable)]
struct Board {
    slots: Vec<Vec<Slot>>
}

#[derive(RustcDecodable, RustcEncodable)]
struct Slot {
    hotel: Option<Hotel>
}

enum Action {
    PlaceTile,
    HandleMergeStocks,
    BuyStocks,
    DrawTile,
    EndGame
}

pub struct PlaceTile {
    player: PlayerId,
    tile: Tile
}

pub struct HandleMergeStocks {
    hold: i8,
    sell: i8,
    trade: i8
}

type BuyStocks = PlayerShares;

#[derive(RustcDecodable, RustcEncodable)]
enum Hotel { Luxor, Tower, American, Festival, Worldwide, Continental, Imperial }

fn empty_shares() -> PlayerShares {
    PlayerShares { luxor: 0, tower: 0, american: 0, festival: 0, worldwide: 0, continental: 0, imperial: 0 }
}

fn new_player(id: PlayerId, tiles: Vec<Tile>) -> Player {
    Player { id: id, money: 6000, shares: empty_shares(), tiles: tiles }
}

fn choose_tiles(tiles: Vec<Tile>, count: usize) -> Vec<Tile> {
    let mut remaining_tiles = tiles;
    let mut random_tiles = Vec::new();
    for _ in 0..count {
        let random_index = (rand::random::<i8>() as usize) % remaining_tiles.len();
        random_tiles.push(remaining_tiles.remove(random_index));
    }
    random_tiles
}

pub fn initial_state() -> Game {
    let slots = (0..COLS)
        .map(|_| (0..ROWS).map(|_| Slot { hotel: None } ).collect() )
        .collect();
    let tiles = (0..TILES).map(|i| Tile { row: i / COLS, col: i % ROWS }).collect();
    let mut chosen_tiles = choose_tiles(tiles, 6*PLAYERS as usize);
    let tiles1 = chosen_tiles.split_off(18);
    let tiles2 = chosen_tiles.split_off(12);
    let tiles3 = chosen_tiles.split_off(6);
    let tiles4 = chosen_tiles;
    let players = vec![
        new_player(1, tiles1),
        new_player(2, tiles2),
        new_player(3, tiles3),
        new_player(4, tiles4)];
    Game {
        board: Board { slots: slots },
        players: players,
        turn: 1,
        merge_decision: None
    }
}
<|endoftext|>


<commit_before>use std::char;
use std::collections::HashMap;
use std::convert::AsRef;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Result;
use std::path::Path;
use std::vec::Vec;

use state::Direction::*;
use util;

extern crate rand;

// Location represents a specific place in the execution space
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Location {
    x: usize,
    y: usize,
}

impl Location {
    //step takes the location and moves in given a direction
    pub fn step(&self, direction: Direction) -> Location {
        let y = match direction {
            Up => self.y.wrapping_sub(1),
            Down => self.y.wrapping_add(1),
            _ => self.y,
        };

        let x = match direction {
            Right => self.x.wrapping_add(1),
            Left => self.x.wrapping_sub(1),
            _ => self.x,
        };

        Location { x: x, y: y }
    }

    //step_mut destructively moves this location in the given direction
    pub fn step_mut(&mut self, direction: Direction) -> Location {
        let next = self.step(direction);
        self.x = next.x;
        self.y = next.y;
        *self

    }

    // new creates a new Location object
    pub fn new(x: usize, y: usize) -> Location {
        Location { x: x, y: y }
    }
}

// Direction represents a specific direction for the interpreter to go
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn opposite(&self) -> Direction {
        match *self {
            Up => Down,
            Left => Right,
            Right => Left,
            Down => Up,
        }
    }

    pub fn up_or_down() -> Direction {
        if rand::random() { Up } else { Down }
    }

    pub fn right_or_left() -> Direction {
        if rand::random() { Right } else { Down }
    }
}

impl Default for Direction {
    fn default() -> Direction {
        Direction::Right
    }
}

impl rand::Rand for Direction {
    fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        let choices = [Up, Down, Left, Right];
        rng.choose(&choices).unwrap().clone()

    }
}
// The current execution mode of this InterpreterState
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Normal, // This intepreter is in the middle of normal execution
    Exited, // This interpreter has reached a terminus for execution
    Quoted, // This interpreter is reading a quoted string
}

impl Default for Mode {
    fn default() -> Mode {
        Mode::Normal
    }
}

// A covenience wrapper around a Vec to produce a stack
#[derive(Default)]
struct Stack {
    stack: Vec<i64>,
}

impl Stack {
    // pop gets the top-most value from the stack, or 0
    pub fn pop(&mut self) -> i64 {
        self.stack.pop().unwrap_or(0)
    }

    // push adds a new number to the top of the stack
    pub fn push(&mut self, item: i64) {
        self.stack.push(item);
    }

    // duplicate_top takes the top most item on the stack (or 0) or pushes it on the stack
    pub fn duplicate_top(&mut self) {
        let value = self.pop();
        self.push(value);
        self.push(value);
    }

    // swap_top takes the top two elements from the stack and reverses them
    pub fn swap_top(&mut self) {
        let a = self.pop();
        let b = self.pop();
        self.push(a);
        self.push(b);
    }
}

// State represents the current state of the map
#[derive(Default)]
pub struct State {
    initial_grid: Vec<Vec<char>>, // the state of the grid when loaded from the file
    grid_updates: HashMap<Location, char>, // any updates to the grid from runtime
    stack: Stack, // the current stack of values pushed from execution
    cursor: Location, // the instruction pointer that shows where we are in the grid
    direction: Direction, // the direction in which the cursor is moving
    execution_mode: Mode, // what execution mode is the interpreter currently in
}

impl State {
    //empty state produces a fresh, empty state object
    pub fn empty_state() -> State {
        Default::default()
    }

    //new_from_file produces a state containing the contents of the file
    pub fn new_from_file<P: AsRef<Path>>(path: P) -> Result<State> {
        let file = File::open(path)?;
        let buf_reader = BufReader::new(file);
        let mut state = State::empty_state();
        for line in buf_reader.lines() {
            let l = line.unwrap_or_default();
            let mut vec = Vec::new();
            for ch in l.chars() {
                vec.push(ch);
            }
            state.initial_grid.push(vec)
        }
        Ok(state)
    }

    // value_at - returns the value at a given location
    pub fn value_at(&self, loc: Location) -> Option<char> {
        if self.grid_updates.contains_key(&loc) {
            return Some(self.grid_updates[&loc]);
        }

        if self.initial_grid.len() >= loc.y {
            return None;
        }

        if self.initial_grid[loc.y].len() >= loc.x {
            return None;
        }

        Some(self.initial_grid[loc.y][loc.x])
    }

    // current_value - gets the value at the current position
    pub fn current_value(&self) -> Option<char> {
        self.value_at(self.cursor.clone())
    }

    // set_value - sets the value at a given location
    pub fn set_value(&mut self, loc: Location, ch: char) {
        self.grid_updates.insert(loc, ch);
    }

    // increment_cursor moves our cursor to the next position - does not wrap
    fn increment_cursor(&mut self) -> Location {
        self.cursor.step_mut(self.direction)
    }

    // next_value increments the cursor and produces the next value if there is one
    fn next_value(&mut self) -> Option<char> {
        self.increment_cursor();
        self.current_value()
    }

    // step_cursor moves the cursor to the next valid space
    pub fn step_cursor(&mut self) -> bool {
        if self.execution_mode == Mode::Exited {
            return false;
        }

        let start = self.cursor;
        while self.next_value().is_none() {
            if start == self.cursor {
                return false;
            }
        }

        true
    }

    // process_quoted reads the current character and pushes it onto the stack if needed
    pub fn process_quoted(&mut self, ch: char) {
        if ch == '"' {
            self.execution_mode = Mode::Normal;
            return;
        }
        self.stack.push(util::char_to_i64(ch));
    }

    // process_normal reads the current character and process it according to normal rules
    pub fn process_normal(&mut self, ch: char) {
        match ch {
            // push digits to the stack
            '0'...'9' | 'a'...'f' => push_digit(self, ch),

            // modal operators
            '"' => self.execution_mode = Mode::Quoted,
            '#' => {self.step_cursor();},

            // arithmetic operators
            '+' => addition(self),
            '-' => subtraction(self),
            '*' => multiply(self),
            '/' => divide(self),
            '%' => modulo(self),

            // logical operators
            '!' => logical_negation(self),
            '`' => greater_than(self),

            // directional operations
            '>' => self.direction = Right,
            '<' => self.direction = Left,
            '^' => self.direction = Up,
            'v' => self.direction = Down,
            '?' => self.direction = rand::random::<Direction>(),

            // branching operators
            '|' => veritical_if(self),
            '_' => horizontal_if(self),

            // stack manipulation operators
            '$' => {self.stack.pop();},
            ':' => self.stack.duplicate_top(),
            '\\' => self.stack.swap_top(),

            // input operators
            '&' => read_integer(self),
            '~' => read_char(self),

            // output operators
            '.' => print_digit(self),
            ',' => print_char(self),

            // load/store operations
            'p' => put(self),
            'g' => get(self),

            // end the program
            '@' => end_program(self),
            _ => (),
        };

    }
}

// read_char reads a character from the user
fn read_char(state : &mut State) {
    let mut input = String::new();
    let mut ch : char = 0 as char;
    if let Ok(_) = io::stdin().read_line(&mut input) {
        if let Some(c) = input.chars().next(){
            ch = c;
        }
    }
    state.stack.push(util::char_to_i64(ch));
}

// read_integer reads a number from the commandline
fn read_integer(state : &mut State) {
    let mut input = String::new();
    if let Ok(_) = io::stdin().read_line(&mut input) {
        if let Ok(value) = input.trim().parse::<i64>() {
            state.stack.push(value);
            return;
        }
    }
    state.stack.push(0);
}

// put pops the values y, x, and v and stores value v at location {x,y}
fn put(state: &mut State) {
    let y = state.stack.pop();
    let x = state.stack.pop();
    let v = state.stack.pop();
    state.set_value(Location{x : x as usize, y : y as usize }, util::i64_to_char(v));
}

// get puts the value at {x, y} onto the stack
fn get(state: &mut State) {
    let y = state.stack.pop();
    let x = state.stack.pop();
    let v = util::char_to_i64(state.value_at(Location{x : x as usize, y : y as usize}).unwrap_or(0 as char));
}

// greater_than tests if b > a
fn greater_than(state : &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    let mut result = 0;
    if b > a {
        result = 1;
    }
    state.stack.push(result);
}

// logical_negation tests if the top most value is 0
fn logical_negation(state : &mut State) {
    let mut negation = 0;
    if state.stack.pop() == 0 {
        negation = 1;
    }
    state.stack.push(negation);
}

// print_digit prints a number from the stack
fn print_digit(state: &mut State) {
    print!("{}", state.stack.pop());
}

// print_char prints the top value on the stack as a char
fn print_char(state: &mut State) {
    print!("{}", util::i64_to_char(state.stack.pop()));
}

// push_digit takes a character and pushs it onto the stack as a digit
fn push_digit(state: &mut State, ch: char) {
    if let Some(v) = ch.to_digit(16) {
        state.stack.push(v as i64);
    }
}

// addition performs addition on the two top values from the stack
fn addition(state: &mut State) {
    let sum = state.stack.pop() + state.stack.pop();
    state.stack.push(sum);
}

// subtraction performs b - a where a is popped from the stack before b
fn subtraction(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b - a);
}

// multiply performs a * b by popping two values from the stack
fn multiply(state: &mut State) {
    let product = state.stack.pop() * state.stack.pop();
    state.stack.push(product);
}

// divide performs b / a => does NOT user prompt
fn divide(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b / a);
}

// modulo performs b % a
fn modulo(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b % a);
}

// end_program sets the program to a terminated state
fn end_program(state: &mut State) {
    state.execution_mode = Mode::Exited;
}

// horizontal_if calculates a vertical branch
fn horizontal_if(state: &mut State) {
    state.direction = Left;
    if state.stack.pop() == 0 {
        state.direction = Right;
    }
}

// veritical_if calculates a horizontal branch
fn veritical_if(state: &mut State) {
    state.direction = Up;
    if state.stack.pop() == 0 {
        state.direction = Down;
    }
}
<commit_msg>Fixing semantic error<commit_after>use std::char;
use std::collections::HashMap;
use std::convert::AsRef;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Result;
use std::path::Path;
use std::vec::Vec;

use state::Direction::*;
use util;

extern crate rand;

// Location represents a specific place in the execution space
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Location {
    x: usize,
    y: usize,
}

impl Location {
    //step takes the location and moves in given a direction
    pub fn step(&self, direction: Direction) -> Location {
        let y = match direction {
            Up => self.y.wrapping_sub(1),
            Down => self.y.wrapping_add(1),
            _ => self.y,
        };

        let x = match direction {
            Right => self.x.wrapping_add(1),
            Left => self.x.wrapping_sub(1),
            _ => self.x,
        };

        Location { x: x, y: y }
    }

    //step_mut destructively moves this location in the given direction
    pub fn step_mut(&mut self, direction: Direction) -> Location {
        let next = self.step(direction);
        self.x = next.x;
        self.y = next.y;
        *self

    }

    // new creates a new Location object
    pub fn new(x: usize, y: usize) -> Location {
        Location { x: x, y: y }
    }
}

// Direction represents a specific direction for the interpreter to go
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn opposite(&self) -> Direction {
        match *self {
            Up => Down,
            Left => Right,
            Right => Left,
            Down => Up,
        }
    }

    pub fn up_or_down() -> Direction {
        if rand::random() { Up } else { Down }
    }

    pub fn right_or_left() -> Direction {
        if rand::random() { Right } else { Down }
    }
}

impl Default for Direction {
    fn default() -> Direction {
        Direction::Right
    }
}

impl rand::Rand for Direction {
    fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        let choices = [Up, Down, Left, Right];
        rng.choose(&choices).unwrap().clone()

    }
}
// The current execution mode of this InterpreterState
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Normal, // This intepreter is in the middle of normal execution
    Exited, // This interpreter has reached a terminus for execution
    Quoted, // This interpreter is reading a quoted string
}

impl Default for Mode {
    fn default() -> Mode {
        Mode::Normal
    }
}

// A covenience wrapper around a Vec to produce a stack
#[derive(Default)]
struct Stack {
    stack: Vec<i64>,
}

impl Stack {
    // pop gets the top-most value from the stack, or 0
    pub fn pop(&mut self) -> i64 {
        self.stack.pop().unwrap_or(0)
    }

    // push adds a new number to the top of the stack
    pub fn push(&mut self, item: i64) {
        self.stack.push(item);
    }

    // duplicate_top takes the top most item on the stack (or 0) or pushes it on the stack
    pub fn duplicate_top(&mut self) {
        let value = self.pop();
        self.push(value);
        self.push(value);
    }

    // swap_top takes the top two elements from the stack and reverses them
    pub fn swap_top(&mut self) {
        let a = self.pop();
        let b = self.pop();
        self.push(a);
        self.push(b);
    }
}

// State represents the current state of the map
#[derive(Default)]
pub struct State {
    initial_grid: Vec<Vec<char>>, // the state of the grid when loaded from the file
    grid_updates: HashMap<Location, char>, // any updates to the grid from runtime
    stack: Stack, // the current stack of values pushed from execution
    cursor: Location, // the instruction pointer that shows where we are in the grid
    direction: Direction, // the direction in which the cursor is moving
    execution_mode: Mode, // what execution mode is the interpreter currently in
}

impl State {
    //empty state produces a fresh, empty state object
    pub fn empty_state() -> State {
        Default::default()
    }

    //new_from_file produces a state containing the contents of the file
    pub fn new_from_file<P: AsRef<Path>>(path: P) -> Result<State> {
        let file = File::open(path)?;
        let buf_reader = BufReader::new(file);
        let mut state = State::empty_state();
        for line in buf_reader.lines() {
            let l = line.unwrap_or_default();
            let mut vec = Vec::new();
            for ch in l.chars() {
                vec.push(ch);
            }
            state.initial_grid.push(vec)
        }
        Ok(state)
    }

    // value_at - returns the value at a given location
    pub fn value_at(&self, loc: Location) -> Option<char> {
        if self.grid_updates.contains_key(&loc) {
            return Some(self.grid_updates[&loc]);
        }

        if self.initial_grid.len() >= loc.y {
            return None;
        }

        if self.initial_grid[loc.y].len() >= loc.x {
            return None;
        }

        Some(self.initial_grid[loc.y][loc.x])
    }

    // current_value - gets the value at the current position
    pub fn current_value(&self) -> Option<char> {
        self.value_at(self.cursor.clone())
    }

    // set_value - sets the value at a given location
    pub fn set_value(&mut self, loc: Location, ch: char) {
        self.grid_updates.insert(loc, ch);
    }

    // increment_cursor moves our cursor to the next position - does not wrap
    fn increment_cursor(&mut self) -> Location {
        self.cursor.step_mut(self.direction)
    }

    // next_value increments the cursor and produces the next value if there is one
    fn next_value(&mut self) -> Option<char> {
        self.step_cursor();
        self.current_value()
    }

    // step_cursor moves the cursor to the next valid space
    pub fn step_cursor(&mut self) -> bool {
        if self.execution_mode == Mode::Exited {
            return false;
        }

        let start = self.cursor;
        while self.next_value().is_none() {
            if start == self.cursor {
                return false;
            }
        }

        true
    }

    // process_quoted reads the current character and pushes it onto the stack if needed
    pub fn process_quoted(&mut self, ch: char) {
        if ch == '"' {
            self.execution_mode = Mode::Normal;
            return;
        }
        self.stack.push(util::char_to_i64(ch));
    }

    // process_normal reads the current character and process it according to normal rules
    pub fn process_normal(&mut self, ch: char) {
        match ch {
            // push digits to the stack
            '0'...'9' | 'a'...'f' => push_digit(self, ch),

            // modal operators
            '"' => self.execution_mode = Mode::Quoted,
            '#' => {self.step_cursor();},

            // arithmetic operators
            '+' => addition(self),
            '-' => subtraction(self),
            '*' => multiply(self),
            '/' => divide(self),
            '%' => modulo(self),

            // logical operators
            '!' => logical_negation(self),
            '`' => greater_than(self),

            // directional operations
            '>' => self.direction = Right,
            '<' => self.direction = Left,
            '^' => self.direction = Up,
            'v' => self.direction = Down,
            '?' => self.direction = rand::random::<Direction>(),

            // branching operators
            '|' => veritical_if(self),
            '_' => horizontal_if(self),

            // stack manipulation operators
            '$' => {self.stack.pop();},
            ':' => self.stack.duplicate_top(),
            '\\' => self.stack.swap_top(),

            // input operators
            '&' => read_integer(self),
            '~' => read_char(self),

            // output operators
            '.' => print_digit(self),
            ',' => print_char(self),

            // load/store operations
            'p' => put(self),
            'g' => get(self),

            // end the program
            '@' => end_program(self),
            _ => (),
        };

    }
}

// read_char reads a character from the user
fn read_char(state : &mut State) {
    let mut input = String::new();
    let mut ch : char = 0 as char;
    if let Ok(_) = io::stdin().read_line(&mut input) {
        if let Some(c) = input.chars().next(){
            ch = c;
        }
    }
    state.stack.push(util::char_to_i64(ch));
}

// read_integer reads a number from the commandline
fn read_integer(state : &mut State) {
    let mut input = String::new();
    if let Ok(_) = io::stdin().read_line(&mut input) {
        if let Ok(value) = input.trim().parse::<i64>() {
            state.stack.push(value);
            return;
        }
    }
    state.stack.push(0);
}

// put pops the values y, x, and v and stores value v at location {x,y}
fn put(state: &mut State) {
    let y = state.stack.pop();
    let x = state.stack.pop();
    let v = state.stack.pop();
    state.set_value(Location{x : x as usize, y : y as usize }, util::i64_to_char(v));
}

// get puts the value at {x, y} onto the stack
fn get(state: &mut State) {
    let y = state.stack.pop();
    let x = state.stack.pop();
    let v = util::char_to_i64(state.value_at(Location{x : x as usize, y : y as usize}).unwrap_or(0 as char));
}

// greater_than tests if b > a
fn greater_than(state : &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    let mut result = 0;
    if b > a {
        result = 1;
    }
    state.stack.push(result);
}

// logical_negation tests if the top most value is 0
fn logical_negation(state : &mut State) {
    let mut negation = 0;
    if state.stack.pop() == 0 {
        negation = 1;
    }
    state.stack.push(negation);
}

// print_digit prints a number from the stack
fn print_digit(state: &mut State) {
    print!("{}", state.stack.pop());
}

// print_char prints the top value on the stack as a char
fn print_char(state: &mut State) {
    print!("{}", util::i64_to_char(state.stack.pop()));
}

// push_digit takes a character and pushs it onto the stack as a digit
fn push_digit(state: &mut State, ch: char) {
    if let Some(v) = ch.to_digit(16) {
        state.stack.push(v as i64);
    }
}

// addition performs addition on the two top values from the stack
fn addition(state: &mut State) {
    let sum = state.stack.pop() + state.stack.pop();
    state.stack.push(sum);
}

// subtraction performs b - a where a is popped from the stack before b
fn subtraction(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b - a);
}

// multiply performs a * b by popping two values from the stack
fn multiply(state: &mut State) {
    let product = state.stack.pop() * state.stack.pop();
    state.stack.push(product);
}

// divide performs b / a => does NOT user prompt
fn divide(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b / a);
}

// modulo performs b % a
fn modulo(state: &mut State) {
    let a = state.stack.pop();
    let b = state.stack.pop();
    state.stack.push(b % a);
}

// end_program sets the program to a terminated state
fn end_program(state: &mut State) {
    state.execution_mode = Mode::Exited;
}

// horizontal_if calculates a vertical branch
fn horizontal_if(state: &mut State) {
    state.direction = Left;
    if state.stack.pop() == 0 {
        state.direction = Right;
    }
}

// veritical_if calculates a horizontal branch
fn veritical_if(state: &mut State) {
    state.direction = Up;
    if state.stack.pop() == 0 {
        state.direction = Down;
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Formatter, Debug};

use gc_error::GcError;
use super::binding::Binding;
use super::js_var::{JsPtrEnum, JsVar};

pub trait JsScope {
    fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<Binding, GcError>;
    fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>), GcError>;
    fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<(), GcError>;
}

#[derive(Clone)]
pub struct NativeFn(fn(Box<JsScope>, Vec<JsVar>) -> JsVar);

impl Debug for NativeFn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "[native_code]")
    }
}
<commit_msg>fix args for NativeFn<commit_after>use std::fmt::{self, Formatter, Debug};

use gc_error::GcError;
use super::binding::Binding;
use super::js_var::{JsPtrEnum, JsVar};

pub trait JsScope {
    fn alloc(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<Binding, GcError>;
    fn load(&self, bnd: &Binding) -> Result<(JsVar, Option<JsPtrEnum>), GcError>;
    fn store(&mut self, var: JsVar, ptr: Option<JsPtrEnum>) -> Result<(), GcError>;
}

#[derive(Clone)]
pub struct NativeFn(fn(Box<JsScope>, Vec<(JsVar, Option<JsPtrEnum>)>) -> JsVar);

impl Debug for NativeFn {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "[native_code]")
    }
}
<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Cannot get field on removed hex {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Cannot set field on removed hex {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "There is no piece at {:?} to move",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied neighbor {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => {
                if hex.iter().any(|&f| match f {
                    Field::Piece => true,
                    Field::Empty => false,
                }) {
                    return false;
                }
            }
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<commit_msg>Refactor empty hex checking in is_hex_removable<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

impl Turn {
    pub fn switch_turns(&mut self) {
        *self = match *self {
            Turn::White => Turn::Black,
            Turn::Black => Turn::White,
        }
    }
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // Conveniently, every other hex has exactly two pieces on it in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Cannot get field on removed hex {:?}", coord),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => hex[coord.f as usize] = field,
            None => panic!("Cannot set field on removed hex {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert_eq!(
            self.get_field(from),
            &Field::Piece,
            "There is no piece at {:?} to move",
            from
        );
        assert!(
            self.get_field_vertex_neighbors(from).contains(to),
            "Cannot move piece at {:?} to non-vertex neighbor {:?}",
            from,
            to
        );
        assert_eq!(
            self.get_field(to),
            &Field::Empty,
            "Cannot move piece at {:?} to occupied neighbor {:?}",
            from,
            to
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => {
                if hex.iter().any(|&f| f == Field::Piece) {
                    return false;
                }
            }
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_idxs: Vec<u32> = coord.get_neighbors().iter().map(|&(i, _)| i).collect();
        let neighbor_idxs_slice = neighbor_idxs.as_slice();

        match neighbor_idxs_slice.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_idxs_slice)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            self.get_hex_neighbors(coord).len(),
        );
        self.set_hex(coord, None);
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<|endoftext|>