<commit_before>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! # Basic Operation
//!
//! redis-rs exposes to API levels: a low- and a high-level part.  The high-level
//! part does not expose all the functionality of redis and might take some
//! liberties in how it speaks the protocol.  The low-level part of the API
//! allows you to express any request on the redis level.  You can fluently
//! switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection().unwrap();
//! }
//! ```
//!
//! You can however also *not* unwrap the client and connection and pass
//! the result containing a client to the functions directly.  Doing this
//! on actual clients is discouraged however as currently no connection
//! pooling takes place and you create and destroy a TCP socket constantly.
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection();
//!     let _ : () = redis::cmd("SET").arg("my_key").arg(42i).query(&con).unwrap();
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection();
//!     let _ : () = con.set("my_key", 42i).unwrap();
//! }
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = con.get("my_counter").unwrap();
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = con.get("missing_key").unwrap();
//! let name : String = con.get("my_name").unwrap();
//! let bin : Vec<u8> = con.get("my_binary").unwrap();
//! let map : HashMap<String, i32> = con.hgetall("my_hash").unwrap();
//! let keys : Vec<String> = con.hkeys("my_hash").unwrap();
//! let mems : HashSet<i32> = con.smembers("my_set").unwrap();
//! let (k1, k2) : (String, String) = con.get(["k1", "k2"].as_slice()).unwrap();
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<int> = redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con).unwrap();
//! for x in iter {
//!     // do something with the item
//! }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .set("key_1", 42i).ignore()
//!     .set("key_2", 43i).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con).unwrap();
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (int,) = redis::transaction(&con, [key].as_slice(), |pipe| {
//!     let old_val : int = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }).unwrap();
//! println!("The incremented number is: {}", new_val);
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let mut pubsub = client.get_pubsub().unwrap();
//! pubsub.subscribe("channel_1").unwrap();
//! pubsub.subscribe("channel_2").unwrap();
//!
//! loop {
//!     let msg = pubsub.get_message().unwrap();
//!     let payload : String = msg.get_payload().unwrap();
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : int = script.arg(1i).arg(2i).invoke(&con).unwrap();
//! assert_eq!(result, 3);
//! ```

#![crate_name = "redis"]
#![crate_type = "lib"]
#![license = "BSD"]
#![comment = "Bindings and wrapper functions for redis."]

#![deny(non_camel_case_types)]

#![feature(macro_rules)]
#![feature(default_type_params)]
#![feature(slicing_syntax)]

#![experimental]

extern crate url;
extern crate serialize;
extern crate "rust-crypto" as crypto;

/* public api */
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo,
                     IntoConnectionInfo, PubSub, Msg, transaction};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{
    Commands,
    PipelineCommands,
};

#[doc(hidden)]
pub use types::{
    /* low level values */
    Value,
        Nil,
        Int,
        Data,
        Bulk,
        Okay,
        Status,

    /* error and result types */
    Error,
    RedisResult,

    /* error kinds */
    ErrorKind,
        ResponseError,
        TypeError,
        ExecAbortError,
        BusyLoadingError,
        NoScriptError,
        ExtensionError,
        InternalIoError,

    /* utility types */
    InfoDict,
    NumericBehavior,
        NonNumeric,
        NumberIsInteger,
        NumberIsFloat,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<commit_msg>Updated docs slightly and exported function previously missing.<commit_after>//! redis-rs is a rust implementation of a Redis client library.  It exposes
//! a general purpose interface to Redis and also provides specific helpers for
//! commonly used functionality.
//!
//! The crate is called `redis` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies.redis]
//! git = "https://github.com/mitsuhiko/redis-rs.git"
//! ```
//!
//! # Basic Operation
//!
//! redis-rs exposes to API levels: a low- and a high-level part.  The high-level
//! part does not expose all the functionality of redis and might take some
//! liberties in how it speaks the protocol.  The low-level part of the API
//! allows you to express any request on the redis level.  You can fluently
//! switch between both API levels at any point.
//!
//! ## Connection Handling
//!
//! For connecting to redis you can use a client object which then can produce
//! actual connections.  Connections and clients as well as results of
//! connections and clients are considered `ConnectionLike` objects and
//! can be used anywhere a request is made.
//!
//! The full canonical way to get a connection is to create a client and
//! to ask for a connection from it:
//!
//! ```rust,no_run
//! extern crate redis;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection().unwrap();
//! }
//! ```
//!
//! You can however also *not* unwrap the client and connection and pass
//! the result containing a client to the functions directly.  Doing this
//! on actual clients is discouraged however as currently no connection
//! pooling takes place and you create and destroy a TCP socket constantly.
//!
//! ## Executing Low-Level Commands
//!
//! To execute low-level commands you can use the `cmd` function which allows
//! you to build redis requests.  Once you have configured a command object
//! to your liking you can send a query into any `ConnectionLike` object:
//!
//! ```rust,no_run
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection();
//!     let _ : () = redis::cmd("SET").arg("my_key").arg(42i).query(&con).unwrap();
//! }
//! ```
//!
//! Upon querying the return value is a result object.  If you do not care
//! about the actual return value (other than that it is not a failure)
//! you can always type annotate it to the unit type `()`.
//!
//! ## Executing High-Level Commands
//!
//! The high-level interface is similar.  For it to become available you
//! need to use the `Commands` trait in which case all `ConnectionLike`
//! objects the library provides will also have high-level methods which
//! make working with the protocol easier:
//!
//! ```rust,no_run
//! extern crate redis;
//! use redis::Commands;
//!
//! fn main() {
//!     let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//!     let con = client.get_connection();
//!     let _ : () = con.set("my_key", 42i).unwrap();
//! }
//! ```
//!
//! Note that high-level commands are work in progress and many are still
//! missing!
//!
//! ## Type Conversions
//!
//! Because redis inherently is mostly type-less and the protocol is not
//! exactly friendly to developers, this library provides flexible support
//! for casting values to the intended results.  This is driven through the
//! `FromRedisValue` and `ToRedisArgs` traits.
//!
//! The `arg` method of the command will accept a wide range of types through
//! the `ToRedisArgs` trait and the `query` method of a command can convert the
//! value to what you expect the function to return through the `FromRedisValue`
//! trait.  This is quite flexible and allows vectors, tuples, hashsets, hashmaps
//! as well as optional values:
//!
//! ```rust,no_run
//! # use redis::Commands;
//! # use std::collections::{HashMap, HashSet};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let count : i32 = con.get("my_counter").unwrap();
//! let count = con.get("my_counter").unwrap_or(0i32);
//! let k : Option<String> = con.get("missing_key").unwrap();
//! let name : String = con.get("my_name").unwrap();
//! let bin : Vec<u8> = con.get("my_binary").unwrap();
//! let map : HashMap<String, i32> = con.hgetall("my_hash").unwrap();
//! let keys : Vec<String> = con.hkeys("my_hash").unwrap();
//! let mems : HashSet<i32> = con.smembers("my_set").unwrap();
//! let (k1, k2) : (String, String) = con.get(["k1", "k2"].as_slice()).unwrap();
//! ```
//!
//! # Iteration Protocol
//!
//! In addition to sending a single query you iterators are also supported.  When
//! used with regular bulk responses they don't give you much over querying and
//! converting into a vector (both use a vector internally) but they can also
//! be used with `SCAN` like commands in which case iteration will send more
//! queries until the cursor is exhausted:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let mut iter : redis::Iter<int> = redis::cmd("SSCAN").arg("my_set")
//!     .cursor_arg(0).iter(&con).unwrap();
//! for x in iter {
//!     // do something with the item
//! }
//! ```
//!
//! As you can see the cursor argument needs to be defined with `cursor_arg`
//! instead of `arg` so that the library knows which argument needs updating
//! as the query is run for more items.
//!
//! # Pipelining
//!
//! In addition to simple queries you can also send command pipelines.  This
//! is provided through the `pipe` function.  It works very similar to sending
//! individual commands but you can send more than one in one go.  This also
//! allows you to ignore individual results so that matching on the end result
//! is easier:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! If you want the pipeline to be wrapped in a `MULTI`/`EXEC` block you can
//! easily do that by switching the pipeline into `atomic` mode.  From the
//! caller's point of view nothing changes, the pipeline itself will take
//! care of the rest for you:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .cmd("SET").arg("key_1").arg(42i).ignore()
//!     .cmd("SET").arg("key_2").arg(43i).ignore()
//!     .cmd("GET").arg("key_1")
//!     .cmd("GET").arg("key_2").query(&con).unwrap();
//! ```
//!
//! You can also use high-level commands on pipelines through the
//! `PipelineCommands` trait:
//!
//! ```rust,no_run
//! use redis::PipelineCommands;
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let (k1, k2) : (i32, i32) = redis::pipe()
//!     .atomic()
//!     .set("key_1", 42i).ignore()
//!     .set("key_2", 43i).ignore()
//!     .get("key_1")
//!     .get("key_2").query(&con).unwrap();
//! ```
//!
//! # Transactions
//!
//! Transactions are available through atomic pipelines.  In order to use
//! them in a more simple way you can use the `transaction` function of a
//! connection:
//!
//! ```rust,no_run
//! use redis::{Commands, PipelineCommands};
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let key = "the_key";
//! let (new_val,) : (int,) = redis::transaction(&con, [key].as_slice(), |pipe| {
//!     let old_val : int = try!(con.get(key));
//!     pipe
//!         .set(key, old_val + 1).ignore()
//!         .get(key).query(&con)
//! }).unwrap();
//! println!("The incremented number is: {}", new_val);
//! ```
//!
//! For more information see the `transaction` function.
//!
//! # PubSub
//!
//! Pubsub is currently work in progress but provided through the `PubSub`
//! connection object.  Due to the fact that Rust does not have support
//! for async IO in libnative yet, the API does not provide a way to
//! read messages with any form of timeout yet.
//!
//! Example usage:
//!
//! ```rust,no_run
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let mut pubsub = client.get_pubsub().unwrap();
//! pubsub.subscribe("channel_1").unwrap();
//! pubsub.subscribe("channel_2").unwrap();
//!
//! loop {
//!     let msg = pubsub.get_message().unwrap();
//!     let payload : String = msg.get_payload().unwrap();
//!     println!("channel '{}': {}", msg.get_channel_name(), payload);
//! }
//! ```
//!
//! # Scripts
//!
//! Lua scripts are supported through the `Script` type in a convenient
//! way (it does not support pipelining currently).  It will automatically
//! load the script if it does not exist and invoke it.
//!
//! Example:
//!
//! ```rust,no_run
//! # let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! # let con = client.get_connection().unwrap();
//! let script = redis::Script::new(r"
//!     return tonumber(ARGV[1]) + tonumber(ARGV[2]);
//! ");
//! let result : int = script.arg(1i).arg(2i).invoke(&con).unwrap();
//! assert_eq!(result, 3);
//! ```

#![crate_name = "redis"]
#![crate_type = "lib"]
#![license = "BSD"]
#![comment = "Bindings and wrapper functions for redis."]

#![deny(non_camel_case_types)]

#![feature(macro_rules)]
#![feature(default_type_params)]
#![feature(slicing_syntax)]

#![experimental]

extern crate url;
extern crate serialize;
extern crate "rust-crypto" as crypto;

/* public api */
pub use parser::{parse_redis_value, Parser};
pub use client::Client;
pub use script::{Script, ScriptInvocation};
pub use connection::{Connection, ConnectionLike, ConnectionInfo,
                     IntoConnectionInfo, PubSub, Msg, transaction,
                     parse_redis_url};
pub use cmd::{cmd, Cmd, pipe, Pipeline, Iter, pack_command};
pub use commands::{
    Commands,
    PipelineCommands,
};

#[doc(hidden)]
pub use types::{
    /* low level values */
    Value,
        Nil,
        Int,
        Data,
        Bulk,
        Okay,
        Status,

    /* error and result types */
    Error,
    RedisResult,

    /* error kinds */
    ErrorKind,
        ResponseError,
        TypeError,
        ExecAbortError,
        BusyLoadingError,
        NoScriptError,
        ExtensionError,
        InternalIoError,

    /* utility types */
    InfoDict,
    NumericBehavior,
        NonNumeric,
        NumberIsInteger,
        NumberIsFloat,

    /* conversion traits */
    FromRedisValue,
    ToRedisArgs,

    /* utility functions */
    from_redis_value,
};

mod macros;

mod parser;
mod client;
mod connection;
mod types;
mod script;
mod cmd;
mod commands;
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

pub const SIGHUP:    ::c_int = 1;
pub const SIGINT:    ::c_int = 2;
pub const SIGQUIT:   ::c_int = 3;
pub const SIGILL:    ::c_int = 4;
pub const SIGTRAP:   ::c_int = 5;
pub const SIGABRT:   ::c_int = 6;
pub const SIGBUS:    ::c_int = 7;
pub const SIGFPE:    ::c_int = 8;
pub const SIGKILL:   ::c_int = 9;
pub const SIGUSR1:   ::c_int = 10;
pub const SIGSEGV:   ::c_int = 11;
pub const SIGUSR2:   ::c_int = 12;
pub const SIGPIPE:   ::c_int = 13;
pub const SIGALRM:   ::c_int = 14;
pub const SIGTERM:   ::c_int = 15;
pub const SIGSTKFLT: ::c_int = 16;
pub const SIGCHLD:   ::c_int = 17;
pub const SIGCONT:   ::c_int = 18;
pub const SIGSTOP:   ::c_int = 19;
pub const SIGTSTP:   ::c_int = 20;
pub const SIGTTIN:   ::c_int = 21;
pub const SIGTTOU:   ::c_int = 22;
pub const SIGURG:    ::c_int = 23;
pub const SIGXCPU:   ::c_int = 24;
pub const SIGXFSZ:   ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF:   ::c_int = 27;
pub const SIGWINCH:  ::c_int = 28;
pub const SIGIO:     ::c_int = 29;
pub const SIGPWR:    ::c_int = 30;
pub const SIGSYS:    ::c_int = 31;

extern {
    pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
    pub fn fchown(fd: ::c_int, uid: ::uid_t, gid: ::gid_t) -> ::c_int;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn gethostname(name: *mut ::c_char, len: ::size_t) -> ::c_int;
    pub fn getpid() -> pid_t;
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t) -> ::ssize_t;
    pub fn setenv(name: *const c_char, val: *const c_char, overwrite: ::c_int) -> ::c_int;
    pub fn unsetenv(name: *const c_char) -> ::c_int;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) -> ::ssize_t;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<commit_msg>Fix style<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

pub const SIGHUP:    ::c_int = 1;
pub const SIGINT:    ::c_int = 2;
pub const SIGQUIT:   ::c_int = 3;
pub const SIGILL:    ::c_int = 4;
pub const SIGTRAP:   ::c_int = 5;
pub const SIGABRT:   ::c_int = 6;
pub const SIGBUS:    ::c_int = 7;
pub const SIGFPE:    ::c_int = 8;
pub const SIGKILL:   ::c_int = 9;
pub const SIGUSR1:   ::c_int = 10;
pub const SIGSEGV:   ::c_int = 11;
pub const SIGUSR2:   ::c_int = 12;
pub const SIGPIPE:   ::c_int = 13;
pub const SIGALRM:   ::c_int = 14;
pub const SIGTERM:   ::c_int = 15;
pub const SIGSTKFLT: ::c_int = 16;
pub const SIGCHLD:   ::c_int = 17;
pub const SIGCONT:   ::c_int = 18;
pub const SIGSTOP:   ::c_int = 19;
pub const SIGTSTP:   ::c_int = 20;
pub const SIGTTIN:   ::c_int = 21;
pub const SIGTTOU:   ::c_int = 22;
pub const SIGURG:    ::c_int = 23;
pub const SIGXCPU:   ::c_int = 24;
pub const SIGXFSZ:   ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF:   ::c_int = 27;
pub const SIGWINCH:  ::c_int = 28;
pub const SIGIO:     ::c_int = 29;
pub const SIGPWR:    ::c_int = 30;
pub const SIGSYS:    ::c_int = 31;

extern {
    pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
    pub fn fchown(fd: ::c_int, uid: ::uid_t, gid: ::gid_t) -> ::c_int;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn gethostname(name: *mut ::c_char, len: ::size_t) -> ::c_int;
    pub fn getpid() -> pid_t;
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t) -> ::ssize_t;
    pub fn setenv(name: *const c_char, val: *const c_char, overwrite: ::c_int)
                  -> ::c_int;
    pub fn unsetenv(name: *const c_char) -> ::c_int;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<|endoftext|>


<commit_before>
use std;
use ffi::*;
use Library;

pub struct GlyphSlot {
    pub bitmap: FT_Bitmap,
    pub bitmap_left: i32,
    pub bitmap_top: i32,

    raw: FT_GlyphSlot,
}

impl GlyphSlot {
    pub fn new(raw: FT_GlyphSlot) -> GlyphSlot {
        unsafe {
            GlyphSlot {
                bitmap: (*raw).bitmap,
                bitmap_left: (*raw).bitmap_left,
                bitmap_top: (*raw).bitmap_top,

                raw: raw,
            }
        }
    }

    pub fn raw(&self) -> FT_GlyphSlot {
        self.raw
    }
}

pub struct Face {
    raw: FT_Face,
}

impl Face {
    pub fn new(library: &Library, filepathname: &str, face_index: i64) -> Result<Face, String> {
        unsafe {
            let face: FT_Face = std::ptr::null();
            let err = FT_New_Face(library.raw(), filepathname.as_slice().as_ptr(), face_index, &face);
            if err == 0 {
                Ok(Face {
                    raw: face,
                })
            } else {
                Err(format!("Failed to create face for '{}'. Error Code: {}", filepathname, err))
            }
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> Result<(), String> {
        unsafe {
            let err = FT_Attach_File(self.raw(), filepathname.as_slice().as_ptr() as *i8);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to attach file '{}'. Error Code: {}", filepathname, err))
            }
        }
    }

    pub fn reference(&self) -> Result<(), String> {
        unsafe {
            let err = FT_Reference_Face(self.raw());
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to reference face. Error Code: {}", err))
            }
        }
    }

    pub fn set_char_size(&self, char_width: i64, char_height: i64, horz_resolution: u32, vert_resolution: u32) -> Result<(), String> {
        unsafe {
            let err = FT_Set_Char_Size(self.raw(), char_width, char_height, horz_resolution, vert_resolution);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to set character size. Error Code: {}", err))
            }
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> Result<(), String> {
        unsafe {
            let err = FT_Load_Glyph(self.raw(), glyph_index, load_flags.bits);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to load glyph of index {}. Error Code: {}", glyph_index, err))
            }
        }
    }

    pub fn load_char(&self, char_code: u64, load_flags: LoadFlag) -> Result<(), String> {
        unsafe {
            let err = FT_Load_Char(self.raw(), char_code, load_flags.bits);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to load character {}. Error Code: {}", char_code, err))
            }
        }
    }

    pub fn glyph(&self) -> GlyphSlot {
        unsafe {
            GlyphSlot::new((*self.raw).glyph)
        }
    }

    pub fn raw(&self) -> FT_Face {
        self.raw
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        unsafe {
            let err = FT_Done_Face(self.raw());
            if err != 0 {
                std::io::println(format!("Failed to drop face. Error Code: {}", err).as_slice());
            }
        }
    }
}

bitflags!(flags LoadFlag: i32 {
    static Default = FT_LOAD_DEFAULT,
    static NoScale = FT_LOAD_NO_SCALE,
    static NoHinting = FT_LOAD_NO_HINTING,
    static Render = FT_LOAD_RENDER,
    static NoBitmap = FT_LOAD_NO_BITMAP,
    static VerticalLayout = FT_LOAD_VERTICAL_LAYOUT,
    static ForceAutohint = FT_LOAD_FORCE_AUTOHINT,
    static CropBitmap = FT_LOAD_CROP_BITMAP,
    static Pendantic = FT_LOAD_PENDANTIC,
    static IgnoreGlobalAdvanceWidth = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    static NoRecurse = FT_LOAD_NO_RECURSE,
    static IgnoreTransform = FT_LOAD_IGNORE_TRANSFORM,
    static Monochrome = FT_LOAD_MONOCHROME,
    static LinearDesign = FT_LOAD_LINEAR_DESIGN,
    static NoAutohint = FT_LOAD_NO_AUTOHINT,
    static Color = FT_LOAD_COLOR
})

<commit_msg>Remove 'GlyphSlot'<commit_after>
use std;
use ffi::*;
use Library;

pub struct Face {
    raw: FT_Face,
}

impl Face {
    pub fn new(library: &Library, filepathname: &str, face_index: i64) -> Result<Face, String> {
        unsafe {
            let face: FT_Face = std::ptr::null();
            let err = FT_New_Face(library.raw(), filepathname.as_slice().as_ptr(), face_index, &face);
            if err == 0 {
                Ok(Face {
                    raw: face,
                })
            } else {
                Err(format!("Failed to create face for '{}'. Error Code: {}", filepathname, err))
            }
        }
    }

    pub fn attach_file(&self, filepathname: &str) -> Result<(), String> {
        unsafe {
            let err = FT_Attach_File(self.raw(), filepathname.as_slice().as_ptr() as *i8);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to attach file '{}'. Error Code: {}", filepathname, err))
            }
        }
    }

    pub fn reference(&self) -> Result<(), String> {
        unsafe {
            let err = FT_Reference_Face(self.raw());
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to reference face. Error Code: {}", err))
            }
        }
    }

    pub fn set_char_size(&self, char_width: i64, char_height: i64, horz_resolution: u32, vert_resolution: u32) -> Result<(), String> {
        unsafe {
            let err = FT_Set_Char_Size(self.raw(), char_width, char_height, horz_resolution, vert_resolution);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to set character size. Error Code: {}", err))
            }
        }
    }

    pub fn load_glyph(&self, glyph_index: u32, load_flags: LoadFlag) -> Result<(), String> {
        unsafe {
            let err = FT_Load_Glyph(self.raw(), glyph_index, load_flags.bits);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to load glyph of index {}. Error Code: {}", glyph_index, err))
            }
        }
    }

    pub fn load_char(&self, char_code: u64, load_flags: LoadFlag) -> Result<(), String> {
        unsafe {
            let err = FT_Load_Char(self.raw(), char_code, load_flags.bits);
            if err == 0 {
                Ok(())
            } else {
                Err(format!("Failed to load character {}. Error Code: {}", char_code, err))
            }
        }
    }

    pub fn glyph<'a>(&'a self) -> &'a FT_GlyphSlotRec {
        unsafe {
            &*(*self.raw).glyph
        }
    }

    pub fn raw(&self) -> FT_Face {
        self.raw
    }
}

impl Drop for Face {
    fn drop(&mut self) {
        unsafe {
            let err = FT_Done_Face(self.raw());
            if err != 0 {
                std::io::println(format!("Failed to drop face. Error Code: {}", err).as_slice());
            }
        }
    }
}

bitflags!(flags LoadFlag: i32 {
    static Default = FT_LOAD_DEFAULT,
    static NoScale = FT_LOAD_NO_SCALE,
    static NoHinting = FT_LOAD_NO_HINTING,
    static Render = FT_LOAD_RENDER,
    static NoBitmap = FT_LOAD_NO_BITMAP,
    static VerticalLayout = FT_LOAD_VERTICAL_LAYOUT,
    static ForceAutohint = FT_LOAD_FORCE_AUTOHINT,
    static CropBitmap = FT_LOAD_CROP_BITMAP,
    static Pendantic = FT_LOAD_PENDANTIC,
    static IgnoreGlobalAdvanceWidth = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
    static NoRecurse = FT_LOAD_NO_RECURSE,
    static IgnoreTransform = FT_LOAD_IGNORE_TRANSFORM,
    static Monochrome = FT_LOAD_MONOCHROME,
    static LinearDesign = FT_LOAD_LINEAR_DESIGN,
    static NoAutohint = FT_LOAD_NO_AUTOHINT,
    static Color = FT_LOAD_COLOR
})

<|endoftext|>


<commit_before>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.1;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 20;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 20.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<commit_msg>the green color must be toned down<commit_after>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.1;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 20;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 80.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(not(windows))]
pub mod posix_perm;
pub mod sys;
#[cfg(windows)]
pub mod win_perm;

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::result;
use std::str::FromStr;

use serde;

pub fn deserialize_using_from_str<'de, T, E, D>(d: D) -> result::Result<T, D::Error>
where
    T: FromStr<Err = E>,
    E: error::Error,
    D: serde::Deserializer<'de>,
{
    struct FromStringable<T, E>(PhantomData<T>, PhantomData<E>);

    impl<'de, T, E> serde::de::Visitor<'de> for FromStringable<T, E>
    where
        T: FromStr<Err = E>,
        E: error::Error,
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string")
        }

        fn visit_str<R>(self, value: &str) -> result::Result<T, R>
        where
            R: serde::de::Error,
        {
            match FromStr::from_str(value) {
                Ok(t) => Ok(t),
                Err(err) => Err(R::custom(format!(
                    "string cannot be parsed: \"{}\" ({})",
                    value,
                    err.description()
                ))),
            }
        }
    }

    d.deserialize_any(FromStringable(PhantomData, PhantomData))
}

pub fn serialize_using_to_string<T, S>(t: &T, s: S) -> result::Result<S::Ok, S::Error>
where
    T: ToString,
    S: serde::Serializer,
{
    s.serialize_str(&t.to_string())
}
<commit_msg>Add trait for converting numeric types to i64<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(not(windows))]
pub mod posix_perm;
pub mod sys;
#[cfg(windows)]
pub mod win_perm;

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::result;
use std::str::FromStr;

use serde;

pub fn deserialize_using_from_str<'de, T, E, D>(d: D) -> result::Result<T, D::Error>
where
    T: FromStr<Err = E>,
    E: error::Error,
    D: serde::Deserializer<'de>,
{
    struct FromStringable<T, E>(PhantomData<T>, PhantomData<E>);

    impl<'de, T, E> serde::de::Visitor<'de> for FromStringable<T, E>
    where
        T: FromStr<Err = E>,
        E: error::Error,
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string")
        }

        fn visit_str<R>(self, value: &str) -> result::Result<T, R>
        where
            R: serde::de::Error,
        {
            match FromStr::from_str(value) {
                Ok(t) => Ok(t),
                Err(err) => Err(R::custom(format!(
                    "string cannot be parsed: \"{}\" ({})",
                    value,
                    err.description()
                ))),
            }
        }
    }

    d.deserialize_any(FromStringable(PhantomData, PhantomData))
}

pub fn serialize_using_to_string<T, S>(t: &T, s: S) -> result::Result<S::Ok, S::Error>
where
    T: ToString,
    S: serde::Serializer,
{
    s.serialize_str(&t.to_string())
}

/// Provide a way to convert numeric types safely to i64
trait ToI64 {
    fn to_i64(self) -> i64;
}

impl ToI64 for usize {
    fn to_i64(self) -> i64 {
        if mem::size_of::<usize>() >= mem::size_of::<i64>() && self > i64::max_value() as usize {
            error!(
                "Tried to convert an out-of-range usize ({}) to i64; using i64::max_value()",
                self
            );
            i64::max_value()
        } else {
            self as i64
        }
    }
}

impl ToI64 for u64 {
    fn to_i64(self) -> i64 {
        if mem::size_of::<u64>() >= mem::size_of::<i64>() && self > i64::max_value() as u64 {
            error!(
                "Tried to convert an out-of-range u64 ({}) to i64; using i64::max_value()",
                self
            );
            i64::max_value()
        } else {
            self as i64
        }
    }
}

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

    #[test]
    fn conversion_of_usize_to_i64() {
        let too_big = usize::max_value();
        let just_right: usize = 42;
        let zero: usize = 0;

        assert_eq!(too_big.to_i64(), i64::max_value());
        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }

    #[test]
    fn conversion_of_u64_to_i64() {
        let too_big = u64::max_value();
        let just_right: u64 = 42;
        let zero: u64 = 0;

        assert_eq!(too_big.to_i64(), i64::max_value());
        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }
}
<|endoftext|>