<commit_before>use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::mem;

use {Value, Table};

#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;

/// A structure to transform Rust values into TOML values.
///
/// This encoder implements the serialization `Encoder` interface, allowing
/// `Encodable` rust types to be fed into the encoder. The output of this
/// encoder is a TOML `Table` structure. The resulting TOML can be stringified
/// if necessary.
///
/// # Example
///
/// ```
/// extern crate rustc_serialize;
/// extern crate toml;
///
/// # fn main() {
/// use toml::{Encoder, Value};
/// use rustc_serialize::Encodable;
///
/// #[derive(RustcEncodable)]
/// struct MyStruct { foo: isize, bar: String }
/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() };
///
/// let mut e = Encoder::new();
/// my_struct.encode(&mut e).unwrap();
///
/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4)))
/// # }
/// ```
#[derive(Default, Debug)]
pub struct Encoder {
    /// Output TOML that is emitted. The current version of this encoder forces
    /// the top-level representation of a structure to be a table.
    ///
    /// This field can be used to extract the return value after feeding a value
    /// into this `Encoder`.
    pub toml: Table,
    state: State,
}

/// Enumeration of errors which can occur while encoding a rust value into a
/// TOML value.
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub enum Error {
    /// Indication that a key was needed when a value was emitted, but no key
    /// was previously emitted.
    NeedsKey,
    /// Indication that a key was emitted, but not value was emitted.
    NoValue,
    /// Indicates that a map key was attempted to be emitted at an invalid
    /// location.
    InvalidMapKeyLocation,
    /// Indicates that a type other than a string was attempted to be used as a
    /// map key type.
    InvalidMapKeyType,
    /// A custom error type was generated
    Custom(String),
}

/// Internal state of the encoder when encoding transitions
#[derive(Debug)]
pub struct EncoderState {
    inner: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Start,
    NextKey(String),
    NextArray(Vec<Value>),
    NextMapKey,
}

impl Default for State {
    fn default() -> State { State::Start }
}

impl Encoder {
    /// Constructs a new encoder which will emit to the given output stream.
    pub fn new() -> Encoder {
        Encoder { state: State::Start, toml: BTreeMap::new() }
    }

    fn emit_value(&mut self, v: Value) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::NextKey(key) => { self.toml.insert(key, v); Ok(()) }
            State::NextArray(mut vec) => {
                // TODO: validate types
                vec.push(v);
                self.state = State::NextArray(vec);
                Ok(())
            }
            State::NextMapKey => {
                match v {
                    Value::String(s) => { self.state = State::NextKey(s); Ok(()) }
                    _ => Err(Error::InvalidMapKeyType)
                }
            }
            _ => Err(Error::NeedsKey)
        }
    }

    fn emit_none(&mut self) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::Start => unreachable!(),
            State::NextKey(_) => Ok(()),
            State::NextArray(..) => panic!("how to encode None in an array?"),
            State::NextMapKey => Err(Error::InvalidMapKeyLocation),
        }
    }

    fn seq_begin(&mut self) -> Result<State, Error> {
        Ok(mem::replace(&mut self.state, State::NextArray(Vec::new())))
    }

    fn seq_end(&mut self, old: State) -> Result<(), Error> {
        match mem::replace(&mut self.state, old) {
            State::NextArray(v) => self.emit_value(Value::Array(v)),
            _ => unreachable!(),
        }
    }

    fn table_key<F>(&mut self, f: F) -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        match mem::replace(&mut self.state, State::NextMapKey) {
            State::Start => {}
            _ => return Err(Error::InvalidMapKeyLocation),
        }
        try!(f(self));
        match self.state {
            State::NextKey(_) => Ok(()),
            _ => Err(Error::InvalidMapKeyLocation),
        }
    }
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.encode(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.serialize(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
    encode(t).to_string()
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String {
    encode(t).to_string()
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NeedsKey => write!(f, "need a key to encode"),
            Error::NoValue => write!(f, "no value to emit for a previous key"),
            Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \
                                                       at this location"),
            Error::InvalidMapKeyType => write!(f, "only strings can be used as \
                                                   key types"),
            Error::Custom(ref s) => write!(f, "custom error: {}", s),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str { "TOML encoding error" }
}
<commit_msg>Fix a typo<commit_after>use std::collections::BTreeMap;
use std::error;
use std::fmt;
use std::mem;

use {Value, Table};

#[cfg(feature = "rustc-serialize")] mod rustc_serialize;
#[cfg(feature = "serde")] mod serde;

/// A structure to transform Rust values into TOML values.
///
/// This encoder implements the serialization `Encoder` interface, allowing
/// `Encodable` rust types to be fed into the encoder. The output of this
/// encoder is a TOML `Table` structure. The resulting TOML can be stringified
/// if necessary.
///
/// # Example
///
/// ```
/// extern crate rustc_serialize;
/// extern crate toml;
///
/// # fn main() {
/// use toml::{Encoder, Value};
/// use rustc_serialize::Encodable;
///
/// #[derive(RustcEncodable)]
/// struct MyStruct { foo: isize, bar: String }
/// let my_struct = MyStruct { foo: 4, bar: "hello!".to_string() };
///
/// let mut e = Encoder::new();
/// my_struct.encode(&mut e).unwrap();
///
/// assert_eq!(e.toml.get(&"foo".to_string()), Some(&Value::Integer(4)))
/// # }
/// ```
#[derive(Default, Debug)]
pub struct Encoder {
    /// Output TOML that is emitted. The current version of this encoder forces
    /// the top-level representation of a structure to be a table.
    ///
    /// This field can be used to extract the return value after feeding a value
    /// into this `Encoder`.
    pub toml: Table,
    state: State,
}

/// Enumeration of errors which can occur while encoding a rust value into a
/// TOML value.
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub enum Error {
    /// Indication that a key was needed when a value was emitted, but no key
    /// was previously emitted.
    NeedsKey,
    /// Indication that a key was emitted, but no value was emitted.
    NoValue,
    /// Indicates that a map key was attempted to be emitted at an invalid
    /// location.
    InvalidMapKeyLocation,
    /// Indicates that a type other than a string was attempted to be used as a
    /// map key type.
    InvalidMapKeyType,
    /// A custom error type was generated
    Custom(String),
}

/// Internal state of the encoder when encoding transitions
#[derive(Debug)]
pub struct EncoderState {
    inner: State,
}

#[derive(PartialEq, Debug)]
enum State {
    Start,
    NextKey(String),
    NextArray(Vec<Value>),
    NextMapKey,
}

impl Default for State {
    fn default() -> State { State::Start }
}

impl Encoder {
    /// Constructs a new encoder which will emit to the given output stream.
    pub fn new() -> Encoder {
        Encoder { state: State::Start, toml: BTreeMap::new() }
    }

    fn emit_value(&mut self, v: Value) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::NextKey(key) => { self.toml.insert(key, v); Ok(()) }
            State::NextArray(mut vec) => {
                // TODO: validate types
                vec.push(v);
                self.state = State::NextArray(vec);
                Ok(())
            }
            State::NextMapKey => {
                match v {
                    Value::String(s) => { self.state = State::NextKey(s); Ok(()) }
                    _ => Err(Error::InvalidMapKeyType)
                }
            }
            _ => Err(Error::NeedsKey)
        }
    }

    fn emit_none(&mut self) -> Result<(), Error> {
        match mem::replace(&mut self.state, State::Start) {
            State::Start => unreachable!(),
            State::NextKey(_) => Ok(()),
            State::NextArray(..) => panic!("how to encode None in an array?"),
            State::NextMapKey => Err(Error::InvalidMapKeyLocation),
        }
    }

    fn seq_begin(&mut self) -> Result<State, Error> {
        Ok(mem::replace(&mut self.state, State::NextArray(Vec::new())))
    }

    fn seq_end(&mut self, old: State) -> Result<(), Error> {
        match mem::replace(&mut self.state, old) {
            State::NextArray(v) => self.emit_value(Value::Array(v)),
            _ => unreachable!(),
        }
    }

    fn table_key<F>(&mut self, f: F) -> Result<(), Error>
        where F: FnOnce(&mut Encoder) -> Result<(), Error>
    {
        match mem::replace(&mut self.state, State::NextMapKey) {
            State::Start => {}
            _ => return Err(Error::InvalidMapKeyLocation),
        }
        try!(f(self));
        match self.state {
            State::NextKey(_) => Ok(()),
            _ => Err(Error::InvalidMapKeyLocation),
        }
    }
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode<T: ::rustc_serialize::Encodable>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.encode(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML value.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode<T: ::serde::Serialize>(t: &T) -> Value {
    let mut e = Encoder::new();
    t.serialize(&mut e).unwrap();
    Value::Table(e.toml)
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(feature = "rustc-serialize")]
pub fn encode_str<T: ::rustc_serialize::Encodable>(t: &T) -> String {
    encode(t).to_string()
}

/// Encodes an encodable value into a TOML string.
///
/// This function expects the type given to represent a TOML table in some form.
/// If encoding encounters an error, then this function will fail the task.
#[cfg(all(not(feature = "rustc-serialize"), feature = "serde"))]
pub fn encode_str<T: ::serde::Serialize>(t: &T) -> String {
    encode(t).to_string()
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::NeedsKey => write!(f, "need a key to encode"),
            Error::NoValue => write!(f, "no value to emit for a previous key"),
            Error::InvalidMapKeyLocation => write!(f, "a map cannot be emitted \
                                                       at this location"),
            Error::InvalidMapKeyType => write!(f, "only strings can be used as \
                                                   key types"),
            Error::Custom(ref s) => write!(f, "custom error: {}", s),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str { "TOML encoding error" }
}
<|endoftext|>


<commit_before>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::env;

pub const RFC_BOT_MENTION: &'static str = "@rfcbot";
pub const GH_ORGS: [&'static str; 3] = ["rust-lang", "rust-lang-nursery", "rust-lang-deprecated"];

lazy_static! {
    pub static ref CONFIG: Config = {
        match init() {
            Ok(c) => {
                info!("Configuration parsed from environment variables.");
                c
            },
            Err(missing) => {
                error!("Unable to load environment variables {:?}", missing);
                panic!("Unable to load environment variables {:?}", missing);
            },
        }
    };
}

#[derive(Debug)]
pub struct Config {
    pub server_port: u32,
    pub db_url: String,
    pub db_pool_size: u32,
    pub github_access_token: String,
    pub github_user_agent: String,
    pub github_webhook_secrets: Vec<String>,
    pub github_interval_mins: u64,
    pub release_interval_mins: u64,
    pub post_comments: bool,
}

impl Config {
    pub fn check(&self) -> bool {
        !self.db_url.is_empty() && !self.github_access_token.is_empty() &&
            !self.github_user_agent.is_empty()
    }
}

const SERVER_PORT: &'static str = "SERVER_PORT";
const DB_URL: &'static str = "DATABASE_URL";
const DB_POOL_SIZE: &'static str = "DATABASE_POOL_SIZE";
const GITHUB_TOKEN: &'static str = "GITHUB_ACCESS_TOKEN";
const GITHUB_WEBHOOK_SECRETS: &'static str = "GITHUB_WEBHOOK_SECRETS";
const GITHUB_UA: &'static str = "GITHUB_USER_AGENT";
const GITHUB_INTERVAL: &'static str = "GITHUB_SCRAPE_INTERVAL";
const RELEASES_INTERVAL: &'static str = "RELEASES_SCRAPE_INTERVAL";
const BUILDBOT_INTERVAL: &'static str = "BUILDBOT_SCRAPE_INTERVAL";
const POST_COMMENTS: &'static str = "POST_COMMENTS";

// this is complex, but we'll shortly need a lot more config items
// so checking them automagically seems like a nice solution
pub fn init() -> Result<Config, Vec<&'static str>> {

    let mut vars: BTreeMap<&'static str, Result<String, _>> = BTreeMap::new();
    let keys = vec![SERVER_PORT,
                    DB_URL,
                    DB_POOL_SIZE,
                    GITHUB_TOKEN,
                    GITHUB_WEBHOOK_SECRETS,
                    GITHUB_UA,
                    GITHUB_INTERVAL,
                    RELEASES_INTERVAL,
                    BUILDBOT_INTERVAL,
                    POST_COMMENTS];

    for var in keys {
        vars.insert(var, env::var(var));
    }

    let all_found = vars.iter().all(|(_, v)| v.is_ok());
    if all_found {
        let mut vars = vars.into_iter()
            .map(|(k, v)| (k, v.unwrap()))
            .collect::<BTreeMap<_, _>>();

        let port = vars.remove(SERVER_PORT).unwrap();
        let port = match port.parse::<u32>() {
            Ok(p) => p,
            Err(_) => return Err(vec![SERVER_PORT]),
        };

        let db_url = vars.remove(DB_URL).unwrap();
        let db_pool_size = vars.remove(DB_POOL_SIZE).unwrap();
        let db_pool_size = match db_pool_size.parse::<u32>() {
            Ok(size) => size,
            Err(_) => return Err(vec![DB_POOL_SIZE]),
        };

        let gh_token = vars.remove(GITHUB_TOKEN).unwrap();
        let gh_ua = vars.remove(GITHUB_UA).unwrap();

        let gh_interval = vars.remove(GITHUB_INTERVAL).unwrap();
        let gh_interval = match gh_interval.parse::<u64>() {
            Ok(interval) => interval,
            Err(_) => return Err(vec![GITHUB_INTERVAL]),
        };

        let rel_interval = vars.remove(RELEASES_INTERVAL).unwrap();
        let rel_interval = match rel_interval.parse::<u64>() {
            Ok(interval) => interval,
            Err(_) => return Err(vec![RELEASES_INTERVAL]),
        };

        let post_comments = vars.remove(POST_COMMENTS).unwrap();
        let post_comments = match post_comments.parse::<bool>() {
            Ok(pc) => pc,
            Err(_) => return Err(vec![POST_COMMENTS]),
        };

        let webhook_secrets = vars.remove(GITHUB_WEBHOOK_SECRETS).unwrap();
        let webhook_secrets = webhook_secrets.split(',').map(String::from).collect();

        Ok(Config {
            server_port: port,
            db_url: db_url,
            db_pool_size: db_pool_size,
            github_access_token: gh_token,
            github_user_agent: gh_ua,
            github_webhook_secrets: webhook_secrets,
            github_interval_mins: gh_interval,
            release_interval_mins: rel_interval,
            post_comments: post_comments,
        })

    } else {

        Err(vars.iter()
            .filter(|&(_, v)| v.is_err())
            .map(|(&k, _)| k)
            .collect())

    }
}
<commit_msg>Remove releases configuration.<commit_after>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::env;

pub const RFC_BOT_MENTION: &'static str = "@rfcbot";
pub const GH_ORGS: [&'static str; 3] = ["rust-lang", "rust-lang-nursery", "rust-lang-deprecated"];

lazy_static! {
    pub static ref CONFIG: Config = {
        match init() {
            Ok(c) => {
                info!("Configuration parsed from environment variables.");
                c
            },
            Err(missing) => {
                error!("Unable to load environment variables {:?}", missing);
                panic!("Unable to load environment variables {:?}", missing);
            },
        }
    };
}

#[derive(Debug)]
pub struct Config {
    pub server_port: u32,
    pub db_url: String,
    pub db_pool_size: u32,
    pub github_access_token: String,
    pub github_user_agent: String,
    pub github_webhook_secrets: Vec<String>,
    pub github_interval_mins: u64,
    pub post_comments: bool,
}

impl Config {
    pub fn check(&self) -> bool {
        !self.db_url.is_empty() && !self.github_access_token.is_empty() &&
            !self.github_user_agent.is_empty()
    }
}

const SERVER_PORT: &'static str = "SERVER_PORT";
const DB_URL: &'static str = "DATABASE_URL";
const DB_POOL_SIZE: &'static str = "DATABASE_POOL_SIZE";
const GITHUB_TOKEN: &'static str = "GITHUB_ACCESS_TOKEN";
const GITHUB_WEBHOOK_SECRETS: &'static str = "GITHUB_WEBHOOK_SECRETS";
const GITHUB_UA: &'static str = "GITHUB_USER_AGENT";
const GITHUB_INTERVAL: &'static str = "GITHUB_SCRAPE_INTERVAL";
const BUILDBOT_INTERVAL: &'static str = "BUILDBOT_SCRAPE_INTERVAL";
const POST_COMMENTS: &'static str = "POST_COMMENTS";

// this is complex, but we'll shortly need a lot more config items
// so checking them automagically seems like a nice solution
pub fn init() -> Result<Config, Vec<&'static str>> {

    let mut vars: BTreeMap<&'static str, Result<String, _>> = BTreeMap::new();
    let keys = vec![SERVER_PORT,
                    DB_URL,
                    DB_POOL_SIZE,
                    GITHUB_TOKEN,
                    GITHUB_WEBHOOK_SECRETS,
                    GITHUB_UA,
                    GITHUB_INTERVAL,
                    BUILDBOT_INTERVAL,
                    POST_COMMENTS];

    for var in keys {
        vars.insert(var, env::var(var));
    }

    let all_found = vars.iter().all(|(_, v)| v.is_ok());
    if all_found {
        let mut vars = vars.into_iter()
            .map(|(k, v)| (k, v.unwrap()))
            .collect::<BTreeMap<_, _>>();

        let port = vars.remove(SERVER_PORT).unwrap();
        let port = match port.parse::<u32>() {
            Ok(p) => p,
            Err(_) => return Err(vec![SERVER_PORT]),
        };

        let db_url = vars.remove(DB_URL).unwrap();
        let db_pool_size = vars.remove(DB_POOL_SIZE).unwrap();
        let db_pool_size = match db_pool_size.parse::<u32>() {
            Ok(size) => size,
            Err(_) => return Err(vec![DB_POOL_SIZE]),
        };

        let gh_token = vars.remove(GITHUB_TOKEN).unwrap();
        let gh_ua = vars.remove(GITHUB_UA).unwrap();

        let gh_interval = vars.remove(GITHUB_INTERVAL).unwrap();
        let gh_interval = match gh_interval.parse::<u64>() {
            Ok(interval) => interval,
            Err(_) => return Err(vec![GITHUB_INTERVAL]),
        };

        let post_comments = vars.remove(POST_COMMENTS).unwrap();
        let post_comments = match post_comments.parse::<bool>() {
            Ok(pc) => pc,
            Err(_) => return Err(vec![POST_COMMENTS]),
        };

        let webhook_secrets = vars.remove(GITHUB_WEBHOOK_SECRETS).unwrap();
        let webhook_secrets = webhook_secrets.split(',').map(String::from).collect();

        Ok(Config {
            server_port: port,
            db_url: db_url,
            db_pool_size: db_pool_size,
            github_access_token: gh_token,
            github_user_agent: gh_ua,
            github_webhook_secrets: webhook_secrets,
            github_interval_mins: gh_interval,
            post_comments: post_comments,
        })

    } else {

        Err(vars.iter()
            .filter(|&(_, v)| v.is_err())
            .map(|(&k, _)| k)
            .collect())

    }
}
<|endoftext|>


<commit_before>extern crate envy;

use std::env::var;

static BASE_URL_KEY: &str = "K2_BASE_URL";
static DEFAULT_BASE_URL: &str = "http://localhost:8080/k2/ctapi/";
static LOG_PATH_KEY: &str = "K2_LOG_PATH";

#[derive(Deserialize)]
struct CtnPn {
    #[serde(rename="K2_CTN")]
    ctn: u16,

    #[serde(rename="K2_PN")]
    pn: u16,
}

pub fn base_url() -> String {
    let mut url = var(BASE_URL_KEY).unwrap_or(DEFAULT_BASE_URL.to_string());
    if !url.trim().ends_with("/") {
        url.push_str("/");
    }

    url
}

pub fn log_path() -> Option<String> {
    match var(LOG_PATH_KEY) {
        Ok(path) => Some(path),
        _ => None,
    }
}

pub fn ctn_or(ctn: u16) -> u16 {
    match envy::from_env::<CtnPn>() {
        Ok(config) => {
            debug!("From env: ctn {}", config.ctn);
            config.ctn
        }
        _ => ctn,
    }
}

pub fn pn_or(pn: u16) -> u16 {
    match envy::from_env::<CtnPn>() {
        Ok(config) => {
            debug!("From env: pn {}", config.pn);
            config.pn
        }
        _ => pn,
    }
}

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

    #[test]
    fn ctn_or_return_env_value_if_pn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 2);
    }

    #[test]
    fn ctn_or_return_given_value_if_pn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);

        env::set_var("K2_CTN", "2");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);
    }

    #[test]
    fn pn_or_return_env_value_if_ctn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let pn = pn_or(1);

        assert_eq!(pn, 4);
    }

    #[test]
    fn pn_or_return_given_value_if_ctn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let pn = pn_or(1);

        assert_eq!(pn, 1);

        env::set_var("K2_PN", "2");
        let pn = pn_or(1);

        assert_eq!(pn, 1);
    }

    #[test]
    fn base_url_return_env_value() {
        env::set_var(BASE_URL_KEY, "a/");
        let url = base_url();

        assert_eq!(url, "a/");

        env::set_var(BASE_URL_KEY, "1");
        let url = base_url();

        assert_eq!(url, "1/");
    }

    #[test]
    fn base_url_return_default_value_if_no_env() {
        env::remove_var(BASE_URL_KEY);
        let url = base_url();

        assert_eq!(url, DEFAULT_BASE_URL);
    }
}
<commit_msg>add test for log_path env handling<commit_after>extern crate envy;

use std::env::var;

static BASE_URL_KEY: &str = "K2_BASE_URL";
static DEFAULT_BASE_URL: &str = "http://localhost:8080/k2/ctapi/";
static LOG_PATH_KEY: &str = "K2_LOG_PATH";

#[derive(Deserialize)]
struct CtnPn {
    #[serde(rename="K2_CTN")]
    ctn: u16,

    #[serde(rename="K2_PN")]
    pn: u16,
}

pub fn base_url() -> String {
    let mut url = var(BASE_URL_KEY).unwrap_or(DEFAULT_BASE_URL.to_string());
    if !url.trim().ends_with("/") {
        url.push_str("/");
    }

    url
}

pub fn log_path() -> Option<String> {
    match var(LOG_PATH_KEY) {
        Ok(path) => Some(path),
        _ => None,
    }
}

pub fn ctn_or(ctn: u16) -> u16 {
    match envy::from_env::<CtnPn>() {
        Ok(config) => {
            debug!("From env: ctn {}", config.ctn);
            config.ctn
        }
        _ => ctn,
    }
}

pub fn pn_or(pn: u16) -> u16 {
    match envy::from_env::<CtnPn>() {
        Ok(config) => {
            debug!("From env: pn {}", config.pn);
            config.pn
        }
        _ => pn,
    }
}

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

    #[test]
    fn ctn_or_return_env_value_if_pn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 2);
    }

    #[test]
    fn ctn_or_return_given_value_if_pn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);

        env::set_var("K2_CTN", "2");
        let ctn = ctn_or(1);

        assert_eq!(ctn, 1);
    }

    #[test]
    fn pn_or_return_env_value_if_ctn_is_set_too() {
        env::set_var("K2_CTN", "2");
        env::set_var("K2_PN", "4");
        let pn = pn_or(1);

        assert_eq!(pn, 4);
    }

    #[test]
    fn pn_or_return_given_value_if_ctn_not_set() {
        env::remove_var("K2_CTN");
        env::remove_var("K2_PN");
        let pn = pn_or(1);

        assert_eq!(pn, 1);

        env::set_var("K2_PN", "2");
        let pn = pn_or(1);

        assert_eq!(pn, 1);
    }

    #[test]
    fn base_url_return_env_value() {
        env::set_var(BASE_URL_KEY, "a/");
        let url = base_url();

        assert_eq!(url, "a/");

        env::set_var(BASE_URL_KEY, "1");
        let url = base_url();

        assert_eq!(url, "1/");
    }

    #[test]
    fn base_url_return_default_value_if_no_env() {
        env::remove_var(BASE_URL_KEY);
        let url = base_url();

        assert_eq!(url, DEFAULT_BASE_URL);
    }

    #[test]
    fn log_path_returns_env_value() {
        env::set_var(LOG_PATH_KEY, "a");
        let path = log_path();

        assert_eq!(path, Some(String::from("a")));
    }

    #[test]
    fn log_path_return_none_if_no_env() {
        env::remove_var(LOG_PATH_KEY);
        let path = log_path();

        assert!(path.is_none());
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use openssl::ssl::SslContext;
use log::LogLevelFilter;

#[derive(Clone)]
pub struct Config {
    pub addr: String,
    pub port: u16,
    pub workers: u8,
    pub ssl: Option<SslContext>,
    pub log_level: LogLevelFilter,
}
<commit_msg>remote compile debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use openssl::ssl::SslContext;
use log::LogLevelFilter;

pub struct Config {
    pub addr: String,
    pub port: u16,
    pub workers: u8,
    pub ssl: Option<SslContext>,
    pub log_level: LogLevelFilter,
}
<|endoftext|>


<commit_before><commit_msg>Reduce bdpt benchmark samples_per_dir<commit_after><|endoftext|>


<commit_before>//! The types of objects that can be drawn by ParView

extern crate nalgebra as na;
extern crate serde;
extern crate rustc_serialize;

//use rustc_serialize::json::{self, Json, ToJson};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error};
use kiss3d::scene::SceneNode;
use kiss3d::window::Window;
use std::collections::{HashSet,HashMap};
use std::collections::hash_map::Entry;
use std::iter::FromIterator;

use palette::Palette;

/// The way to ID an object. This is basically a list of strings.
///
/// Each item in the string corresponds to a level in a hierarchy, so that groupings can be made.
/// For example, a protein might have levels:
/// ResidueName → ResidueNumber → Element → AtomName
/// Each must be unique.
#[derive(Debug,Eq,PartialEq,Ord,PartialOrd,Hash,Clone)]
pub struct ObjectID(pub Vec<String>);

impl Serialize for ObjectID {
    fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
        let &ObjectID(ref names) = self;
        names.serialize(s)
    }
}

impl rustc_serialize::Encodable for ObjectID {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let &ObjectID(ref names) = self;
        names.encode(s)
    }
}

impl Deserialize for ObjectID {
    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
        Vec::deserialize(d).map(|n| ObjectID(n))
    }
}

impl rustc_serialize::Decodable for ObjectID {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Vec::decode(d).map(|n| ObjectID(n))
    }
}

impl ObjectID{
    /// Create a new `ObjectTracker` associated with a given `Window`.
    pub fn new(names : Vec<String>) -> ObjectID {
        ObjectID(names)
    }
}

#[derive(Deserialize, Serialize, Clone)]
/// A single frame, which is a series of spheres
pub struct Frame {
    /// the spheres
    pub spheres : Vec<Sphere>,
    /// Text to display
    pub text : Option<String>
}

/// An object that will be drawable by Parview.
///
/// This is the trait-based interface so that Parview can manage it.
/// See Sphere, etc. for objects to implement.
pub trait Object : Clone {
    /// The ID of an object. Must be unique.
    fn id(&self) -> &ObjectID;
    /// Create a new node for this object.
    fn new_node(&self, window : &mut SceneNode) -> SceneNode;
    /// If `self` is the "old" sphere, and `other` is the new one, then for each difference,
    /// Update `self` and the corresponding SceneNode to match
    fn update(&mut self, other: &Self, nodes: &mut SceneNode);
}

/// Keeps track of what `Object` maps to what `SceneNode`, and handles updates
pub struct ObjectTracker<T : Object> {
    /// The set of objects
    objects : HashMap<ObjectID, (T, SceneNode)>,
    /// The scene to which to attach new objects
    parent : SceneNode
}

// TODO: Should this be something like this:
/*
/// Tracks all objects, regardless of type
pub struct ObjectTracker<'a> {
    objects : AnyMap<HashMap<&'a ObjectID, (T, SceneNode)>>,
}
*/

impl<T : Object> ObjectTracker<T> {
    /// Create a new `ObjectTracker` associated with a given `Window`.
    pub fn new(window: &mut Window) -> ObjectTracker<T> {
        ObjectTracker{
            objects: HashMap::new(),
            parent: window.add_group()
        }
    }

    /// The meat of `ObjectTracker`. Update old objects and the scene to match
    /// new objects
    pub fn update<'a, I : Iterator<Item=&'a T>>(&'a mut self, iter : I, palette : &mut Palette) {
        // TODO: this used to be &ObjectID, which is probably faster
        let mut seen : HashSet<ObjectID> = FromIterator::from_iter(self.objects.keys()
            .map(|ref k|{(*k).clone()}));

        for new_object in iter {
            let name : & ObjectID = new_object.id();
            match self.objects.entry(name.clone()) {
                Entry::Occupied(mut entry) => {
                    let &mut (ref mut obj, ref mut node) = entry.get_mut();
                    obj.update(&new_object, node);
                    palette.set_color(obj.id(), node);
                    //let is_invisible = node.data().is_root();
                    // if is_invisible {
                    //     self.parent.add_child(node);
                    // }
                    seen.remove(name);
                }
                Entry::Vacant(v) => {
                    let mut node = new_object.new_node(&mut self.parent);
                    palette.set_color(new_object.id(), &mut node);
                    let _ = v.insert((new_object.clone(), node));
                }
            }
        }

        for k in seen {
            let _ = self.objects.get_mut(&k).map(|&mut (_, ref mut node)| {
                let _ = node.unlink();
            });
            let _ = self.objects.remove(&k);
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
/// A single frame, containing spheres
/// format is (location, diameter, Option(color triple))
pub struct Sphere {
    /// location of the sphere
    pub loc : (f32,f32,f32),
    /// Diameter
    pub diameter : f32,
    /// Color. if none, one will be assigned
    pub names : ObjectID,
}

impl Sphere {
    /// get the location as a Vec3
    pub fn x(&self) -> na::Vec3<f32> {
        let (x,y,z) = self.loc;
        na::Vec3::new(x,y,z)
    }
}

impl Object for Sphere {
    fn id(&self) -> &ObjectID {&self.names}

    fn new_node(&self, parent : &mut SceneNode) -> SceneNode {
        let mut node = parent.add_sphere(self.diameter);
        node.set_local_translation(self.x());

        node
    }

    fn update(&mut self, other: &Self, node: &mut SceneNode){
        if self.diameter != other.diameter {
            self.diameter = other.diameter;
            node.set_local_scale(self.diameter, self.diameter, self.diameter);
        }

        if self.loc != other.loc {
            self.loc = other.loc;
            node.set_local_translation(self.x());
        }
    }
}
<commit_msg>Added Spherocylinder object, but not used<commit_after>//! The types of objects that can be drawn by ParView

extern crate nalgebra as na;
extern crate serde;
extern crate rustc_serialize;

//use rustc_serialize::json::{self, Json, ToJson};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error};
use kiss3d::scene::SceneNode;
use kiss3d::window::Window;
use std::collections::{HashSet,HashMap};
use std::collections::hash_map::Entry;
use std::iter::FromIterator;

use na::{RotationTo,Rotation,Norm};

use palette::Palette;

const EPSILON : f32 = 1e-6;

/// The way to ID an object. This is basically a list of strings.
///
/// Each item in the string corresponds to a level in a hierarchy, so that groupings can be made.
/// For example, a protein might have levels:
/// ResidueName → ResidueNumber → Element → AtomName
/// Each must be unique.
#[derive(Debug,Eq,PartialEq,Ord,PartialOrd,Hash,Clone)]
pub struct ObjectID(pub Vec<String>);

impl Serialize for ObjectID {
    fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
        let &ObjectID(ref names) = self;
        names.serialize(s)
    }
}

impl rustc_serialize::Encodable for ObjectID {
    fn encode<S: rustc_serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let &ObjectID(ref names) = self;
        names.encode(s)
    }
}

impl Deserialize for ObjectID {
    fn deserialize<D: Deserializer>(d: &mut D) -> Result<Self, D::Error> {
        Vec::deserialize(d).map(|n| ObjectID(n))
    }
}

impl rustc_serialize::Decodable for ObjectID {
    fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
        Vec::decode(d).map(|n| ObjectID(n))
    }
}

impl ObjectID{
    /// Create a new `ObjectTracker` associated with a given `Window`.
    pub fn new(names : Vec<String>) -> ObjectID {
        ObjectID(names)
    }
}

#[derive(Deserialize, Serialize, Clone)]
/// A single frame, which is a series of spheres
pub struct Frame {
    /// the spheres
    pub spheres : Vec<Sphere>,
    /// Text to display
    pub text : Option<String>
}

/// An object that will be drawable by Parview.
///
/// This is the trait-based interface so that Parview can manage it.
/// See Sphere, etc. for objects to implement.
pub trait Object : Clone {
    /// The ID of an object. Must be unique.
    fn id(&self) -> &ObjectID;
    /// Create a new node for this object.
    fn new_node(&self, window : &mut SceneNode) -> SceneNode;
    /// If `self` is the "old" sphere, and `other` is the new one, then for each difference,
    /// Update `self` and the corresponding SceneNode to match
    fn update(&mut self, other: &Self, nodes: &mut SceneNode);
}

/// Keeps track of what `Object` maps to what `SceneNode`, and handles updates
pub struct ObjectTracker<T : Object> {
    /// The set of objects
    objects : HashMap<ObjectID, (T, SceneNode)>,
    /// The scene to which to attach new objects
    parent : SceneNode
}

// TODO: Should this be something like this:
/*
/// Tracks all objects, regardless of type
pub struct ObjectTracker<'a> {
    objects : AnyMap<HashMap<&'a ObjectID, (T, SceneNode)>>,
}
*/

impl<T : Object> ObjectTracker<T> {
    /// Create a new `ObjectTracker` associated with a given `Window`.
    pub fn new(window: &mut Window) -> ObjectTracker<T> {
        ObjectTracker{
            objects: HashMap::new(),
            parent: window.add_group()
        }
    }

    /// The meat of `ObjectTracker`. Update old objects and the scene to match
    /// new objects
    pub fn update<'a, I : Iterator<Item=&'a T>>(&'a mut self, iter : I, palette : &mut Palette) {
        // TODO: this used to be &ObjectID, which is probably faster
        let mut seen : HashSet<ObjectID> = FromIterator::from_iter(self.objects.keys()
            .map(|ref k|{(*k).clone()}));

        for new_object in iter {
            let name : & ObjectID = new_object.id();
            match self.objects.entry(name.clone()) {
                Entry::Occupied(mut entry) => {
                    let &mut (ref mut obj, ref mut node) = entry.get_mut();
                    obj.update(&new_object, node);
                    palette.set_color(obj.id(), node);
                    //let is_invisible = node.data().is_root();
                    // if is_invisible {
                    //     self.parent.add_child(node);
                    // }
                    seen.remove(name);
                }
                Entry::Vacant(v) => {
                    let mut node = new_object.new_node(&mut self.parent);
                    palette.set_color(new_object.id(), &mut node);
                    let _ = v.insert((new_object.clone(), node));
                }
            }
        }

        for k in seen {
            let _ = self.objects.get_mut(&k).map(|&mut (_, ref mut node)| {
                let _ = node.unlink();
            });
            let _ = self.objects.remove(&k);
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
/// Data object for a spherical particle
pub struct Sphere {
    /// location of the sphere
    pub loc : (f32,f32,f32),
    /// Diameter
    pub diameter : f32,
    /// Color. if none, one will be assigned
    pub names : ObjectID,
}

impl Sphere {
    /// get the location as a Vec3
    pub fn x(&self) -> na::Vec3<f32> {
        let (x,y,z) = self.loc;
        na::Vec3::new(x,y,z)
    }
}

impl Object for Sphere {
    fn id(&self) -> &ObjectID {&self.names}

    fn new_node(&self, parent : &mut SceneNode) -> SceneNode {
        let mut node = parent.add_sphere(self.diameter);
        node.set_local_translation(self.x());

        node
    }

    fn update(&mut self, other: &Self, node: &mut SceneNode){
        if self.diameter != other.diameter {
            self.diameter = other.diameter;
            node.set_local_scale(self.diameter, self.diameter, self.diameter);
        }

        if self.loc != other.loc {
            self.loc = other.loc;
            node.set_local_translation(self.x());
        }
    }
}

#[derive(Deserialize, Serialize, Clone)]
/// Data object for a spherocylindrical particle
pub struct Spherocylinder {
    /// location of the sphere
    pub loc : (f32,f32,f32),
    /// The central axis of the sphere
    pub axis : (f32,f32,f32),
    /// Diameter
    pub diameter : f32,
    /// Color. if none, one will be assigned
    pub names : ObjectID,
}

impl Spherocylinder {
    /// get the location as a Vec3
    pub fn x(&self) -> na::Vec3<f32> {
        let (x,y,z) = self.loc;
        na::Vec3::new(x,y,z)
    }

    /// get the axis as a Vec3
    pub fn get_axis(&self) -> na::Vec3<f32> {
        let (x,y,z) = self.axis;
        na::Vec3::new(x,y,z)
    }
}

impl Object for Spherocylinder {
    fn id(&self) -> &ObjectID {&self.names}

    fn new_node(&self, parent : &mut SceneNode) -> SceneNode {
        let mut node = parent.add_sphere(self.diameter);
        node.set_local_translation(self.x());

        let z = na::Vec3::new(0., 0., 1.);
        let rot = z.rotation_to(&self.get_axis()).rotation();
        node.set_local_translation(rot);

        node
    }

    fn update(&mut self, other: &Self, node: &mut SceneNode){
        let diameter_change = (other.diameter - self.diameter).abs();
        let length_change = (other.get_axis().norm() - self.get_axis().norm()).abs();

        if diameter_change > EPSILON || length_change > EPSILON {
            if (diameter_change - length_change).abs() > EPSILON {
                panic!("Don't know how to stretch spherocylinders.")
            }

            self.diameter = other.diameter;
            self.axis = other.axis;
            node.set_local_scale(self.diameter, self.diameter, self.diameter);
        }

        if self.loc != other.loc {
            self.loc = other.loc;
            node.set_local_translation(self.x());
        }

        let axis_change = (other.get_axis() - self.get_axis()).norm().abs();
        if axis_change > EPSILON {
            self.axis = other.axis;
            let z = na::Vec3::new(0., 0., 1.);
            let rot = z.rotation_to(&self.get_axis()).rotation();
            node.set_local_translation(rot);
        }
    }
}
<|endoftext|>


<commit_before>// only-linux
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]
extern crate libc;

use std::mem::MaybeUninit;
use std::ptr;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::{Duration, Instant};

fn wake_nobody() {
    let futex = 0;

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }

    // Same, but without omitting the unused arguments.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
            ptr::null::<libc::timespec>(),
            0usize,
            0,
        ), 0);
    }
}

fn wake_dangling() {
    let futex = Box::new(0);
    let ptr: *const i32 = &*futex;
    drop(futex);

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            ptr,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }
}

fn wait_wrong_val() {
    let futex: i32 = 123;

    // Only wait if the futex value is 456.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            456,
            ptr::null::<libc::timespec>(),
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::EAGAIN);
    }
}

fn wait_timeout() {
    let start = Instant::now();

    let futex: i32 = 123;

    // Wait for 200ms, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            123,
            &libc::timespec {
                tv_sec: 0,
                tv_nsec: 200_000_000,
            },
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_absolute_timeout() {
    let start = Instant::now();

    // Get the current monotonic timestamp as timespec.
    let mut timeout = unsafe {
        let mut now: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
        assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0);
        now.assume_init()
    };

    // Add 200ms.
    timeout.tv_nsec += 200_000_000;
    if timeout.tv_nsec > 1_000_000_000 {
        timeout.tv_nsec -= 1_000_000_000;
        timeout.tv_sec += 1;
    }

    let futex: i32 = 123;

    // Wait for 200ms from now, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT_BITSET,
            123,
            &timeout,
            0usize,
            u32::MAX,
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_wake() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    let t = thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE,
                10, // Wake up at most 10 threads.
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT,
            0,
            ptr::null::<libc::timespec>(),
        ), 0);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
    t.join().unwrap();
}

fn wait_wake_bitset() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    let t = thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE_BITSET,
                10, // Wake up at most 10 threads.
                ptr::null::<libc::timespec>(),
                0usize,
                0b1001, // bitset
            ), 0); // Didn't match any thread.
        }
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE_BITSET,
                10, // Wake up at most 10 threads.
                ptr::null::<libc::timespec>(),
                0usize,
                0b0110, // bitset
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT_BITSET,
            0,
            ptr::null::<libc::timespec>(),
            0usize,
            0b0100, // bitset
        ), 0);
    }

    assert!((400..1000).contains(&start.elapsed().as_millis()));
    t.join().unwrap();
}

const FREE: i32 = 0;
const HELD: i32 = 1;
fn concurrent_wait_wake() {
    static FUTEX: AtomicI32 = AtomicI32::new(0);
    for _ in 0..100 {
        // Suppose the main thread is holding a lock implemented using futex...
        FUTEX.store(HELD, Ordering::Relaxed);

        let t = thread::spawn(move || {
            // If this syscall runs first, then we'll be woken up by
            // the main thread's FUTEX_WAKE, and all is fine.
            //
            // If this sycall runs after the main thread's store
            // and FUTEX_WAKE, the syscall must observe that
            // the FUTEX is FREE != HELD and return without waiting
            // or we'll deadlock.
            unsafe {
                libc::syscall(
                    libc::SYS_futex,
                    &FUTEX as *const AtomicI32,
                    libc::FUTEX_WAIT,
                    HELD,
                    ptr::null::<libc::timespec>(),
                );
            }
        });

        FUTEX.store(FREE, Ordering::Relaxed);
        unsafe {
            libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const AtomicI32,
                libc::FUTEX_WAKE,
                1,
            );
        }

        t.join().unwrap();
    }
}

fn main() {
    wake_nobody();
    wake_dangling();
    wait_wrong_val();
    wait_timeout();
    wait_absolute_timeout();
    wait_wake();
    wait_wake_bitset();
    concurrent_wait_wake();
}
<commit_msg>Reduce the number of iterations<commit_after>// only-linux
// compile-flags: -Zmiri-disable-isolation

#![feature(rustc_private)]
extern crate libc;

use std::mem::MaybeUninit;
use std::ptr;
use std::sync::atomic::AtomicI32;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::{Duration, Instant};

fn wake_nobody() {
    let futex = 0;

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }

    // Same, but without omitting the unused arguments.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAKE,
            1,
            ptr::null::<libc::timespec>(),
            0usize,
            0,
        ), 0);
    }
}

fn wake_dangling() {
    let futex = Box::new(0);
    let ptr: *const i32 = &*futex;
    drop(futex);

    // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            ptr,
            libc::FUTEX_WAKE,
            1,
        ), 0);
    }
}

fn wait_wrong_val() {
    let futex: i32 = 123;

    // Only wait if the futex value is 456.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            456,
            ptr::null::<libc::timespec>(),
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::EAGAIN);
    }
}

fn wait_timeout() {
    let start = Instant::now();

    let futex: i32 = 123;

    // Wait for 200ms, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT,
            123,
            &libc::timespec {
                tv_sec: 0,
                tv_nsec: 200_000_000,
            },
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_absolute_timeout() {
    let start = Instant::now();

    // Get the current monotonic timestamp as timespec.
    let mut timeout = unsafe {
        let mut now: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
        assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0);
        now.assume_init()
    };

    // Add 200ms.
    timeout.tv_nsec += 200_000_000;
    if timeout.tv_nsec > 1_000_000_000 {
        timeout.tv_nsec -= 1_000_000_000;
        timeout.tv_sec += 1;
    }

    let futex: i32 = 123;

    // Wait for 200ms from now, with nobody waking us up early.
    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &futex as *const i32,
            libc::FUTEX_WAIT_BITSET,
            123,
            &timeout,
            0usize,
            u32::MAX,
        ), -1);
        assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn wait_wake() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    let t = thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE,
                10, // Wake up at most 10 threads.
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT,
            0,
            ptr::null::<libc::timespec>(),
        ), 0);
    }

    assert!((200..1000).contains(&start.elapsed().as_millis()));
    t.join().unwrap();
}

fn wait_wake_bitset() {
    let start = Instant::now();

    static FUTEX: i32 = 0;

    let t = thread::spawn(move || {
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE_BITSET,
                10, // Wake up at most 10 threads.
                ptr::null::<libc::timespec>(),
                0usize,
                0b1001, // bitset
            ), 0); // Didn't match any thread.
        }
        thread::sleep(Duration::from_millis(200));
        unsafe {
            assert_eq!(libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const i32,
                libc::FUTEX_WAKE_BITSET,
                10, // Wake up at most 10 threads.
                ptr::null::<libc::timespec>(),
                0usize,
                0b0110, // bitset
            ), 1); // Woken up one thread.
        }
    });

    unsafe {
        assert_eq!(libc::syscall(
            libc::SYS_futex,
            &FUTEX as *const i32,
            libc::FUTEX_WAIT_BITSET,
            0,
            ptr::null::<libc::timespec>(),
            0usize,
            0b0100, // bitset
        ), 0);
    }

    assert!((400..1000).contains(&start.elapsed().as_millis()));
    t.join().unwrap();
}

const FREE: i32 = 0;
const HELD: i32 = 1;
fn concurrent_wait_wake() {
    static FUTEX: AtomicI32 = AtomicI32::new(0);
    for _ in 0..20 {
        // Suppose the main thread is holding a lock implemented using futex...
        FUTEX.store(HELD, Ordering::Relaxed);

        let t = thread::spawn(move || {
            // If this syscall runs first, then we'll be woken up by
            // the main thread's FUTEX_WAKE, and all is fine.
            //
            // If this sycall runs after the main thread's store
            // and FUTEX_WAKE, the syscall must observe that
            // the FUTEX is FREE != HELD and return without waiting
            // or we'll deadlock.
            unsafe {
                libc::syscall(
                    libc::SYS_futex,
                    &FUTEX as *const AtomicI32,
                    libc::FUTEX_WAIT,
                    HELD,
                    ptr::null::<libc::timespec>(),
                );
            }
        });

        FUTEX.store(FREE, Ordering::Relaxed);
        unsafe {
            libc::syscall(
                libc::SYS_futex,
                &FUTEX as *const AtomicI32,
                libc::FUTEX_WAKE,
                1,
            );
        }

        t.join().unwrap();
    }
}

fn main() {
    wake_nobody();
    wake_dangling();
    wait_wrong_val();
    wait_timeout();
    wait_absolute_timeout();
    wait_wake();
    wait_wake_bitset();
    concurrent_wait_wake();
}
<|endoftext|>


<commit_before>//! OpenGL back-end for Rust-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{opengl, glsl};
use graphics::{ Context, DrawState, Graphics };
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    use shader_version::glsl::GLSL;
    match glsl {
        GLSL::_1_10 => panic!("GLSL 1.10 not supported"),
        GLSL::_1_20
      | GLSL::_1_30
      | GLSL::_1_40 => for_120,
        _ => for_150,
    }
}

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: glsl::GLSL) -> Colored {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_COLORED_120, VS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_COLORED_120, FS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_ptr());
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: glsl::GLSL) -> Textured {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_TEXTURED_120, VS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_TEXTURED_120, FS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_ptr());
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: opengl::OpenGL) -> GlGraphics {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Draws graphics.
    pub fn draw<F>(&mut self, viewport: [i32; 4], f: F)
        where
            F: FnOnce(Context, &mut GlGraphics)
    {
        let [x, y, w, h] = viewport;
        self.viewport(x, y, w, h);
        self.clear_program();
        self.enable_alpha_blend();
        let c = Context::abs(
            w as f64,
            h as f64
        );
        f(c, self);
        self.disable_alpha_blend();
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear(&mut self, color: [f32; 4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn tri_list<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::CullFace(gl::FRONT_AND_BACK);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_fail]
fn test_gl_loaded() {
    GlGraphics::new(opengl::OpenGL::_3_2);
}
<commit_msg>Disable cull face<commit_after>//! OpenGL back-end for Rust-Graphics.

// External crates.
use std::ffi::CString;
use shader_version::{opengl, glsl};
use graphics::{ Context, DrawState, Graphics };
use gl;
use gl::types::{
    GLint,
    GLsizei,
    GLuint,
};
use shader_utils::{
    compile_shader,
    DynamicAttribute,
};

// Local crate.
use Texture;

static VS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static VS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;

void main()
{
    gl_Position = pos;
}
";

static FS_COLORED_120: &'static str = "
#version 120
uniform vec4 color;

void main()
{
    gl_FragColor = color;
}
";

static FS_COLORED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

out vec4 out_color;

void main()
{
    out_color = color;
}
";

static VS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;

attribute vec4 pos;
attribute vec2 uv;

uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static VS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;

in vec4 pos;
in vec2 uv;

uniform sampler2D s_texture;

out vec2 v_uv;

void main()
{
    v_uv = uv;
    gl_Position = pos;
}
";

static FS_TEXTURED_120: &'static str = "
#version 120
uniform vec4 color;
uniform sampler2D s_texture;

varying vec2 v_uv;

void main()
{
    gl_FragColor = texture2D(s_texture, v_uv) * color;
}
";

static FS_TEXTURED_150_CORE: &'static str = "
#version 150 core
uniform vec4 color;
uniform sampler2D s_texture;

out vec4 out_color;

in vec2 v_uv;

void main()
{
    out_color = texture(s_texture, v_uv) * color;
}
";

fn pick_120_150<T>(glsl: glsl::GLSL, for_120: T, for_150: T) -> T {
    use shader_version::glsl::GLSL;
    match glsl {
        GLSL::_1_10 => panic!("GLSL 1.10 not supported"),
        GLSL::_1_20
      | GLSL::_1_30
      | GLSL::_1_40 => for_120,
        _ => for_150,
    }
}

struct Colored {
    vao: GLuint,
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    pos: DynamicAttribute,
    color: GLint,
}

impl Drop for Colored {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Colored {
    fn new(glsl: glsl::GLSL) -> Colored {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_COLORED_120, VS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_COLORED_120, FS_COLORED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_ptr());
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        Colored {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
        }
    }
}

struct Textured {
    vertex_shader: GLuint,
    fragment_shader: GLuint,
    program: GLuint,
    vao: GLuint,
    color: GLint,
    pos: DynamicAttribute,
    uv: DynamicAttribute,
}

impl Drop for Textured {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteVertexArrays(1, &self.vao);
            gl::DeleteProgram(self.program);
            gl::DeleteShader(self.vertex_shader);
            gl::DeleteShader(self.fragment_shader);
        }
    }
}

impl Textured {
    fn new(glsl: glsl::GLSL) -> Textured {
        let vertex_shader = match compile_shader(
            gl::VERTEX_SHADER,                  // shader type
            pick_120_150(glsl, VS_TEXTURED_120, VS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };
        let fragment_shader = match compile_shader(
            gl::FRAGMENT_SHADER,                // shader type
            pick_120_150(glsl, FS_TEXTURED_120, FS_TEXTURED_150_CORE)
        ) {
            Ok(id) => id,
            Err(s) => panic!("compile_shader: {}", s)
        };

        let program;
        unsafe {
            program = gl::CreateProgram();
            gl::AttachShader(program, vertex_shader);
            gl::AttachShader(program, fragment_shader);

            gl::BindFragDataLocation(program, 0,
                CString::new("out_color".as_bytes()).unwrap().as_ptr());
        }

        let mut vao = 0;
        unsafe {
            gl::GenVertexArrays(1, &mut vao);
            gl::LinkProgram(program);
        }
        let pos = DynamicAttribute::xy(
                program,
                "pos",
                vao
            ).unwrap();
        let color = unsafe {
                gl::GetUniformLocation(program,
                    CString::new("color".as_bytes()).unwrap().as_ptr())
            };
        if color == -1 {
            panic!("Could not find uniform `color`");
        }
        let uv = DynamicAttribute::uv(
                program,
                "uv",
                vao
            ).unwrap();
        Textured {
            vao: vao,
            vertex_shader: vertex_shader,
            fragment_shader: fragment_shader,
            program: program,
            pos: pos,
            color: color,
            uv: uv,
        }
    }
}

// Newlines and indents for cleaner panic message.
const GL_FUNC_NOT_LOADED: &'static str = "
    OpenGL function pointers must be loaded before creating the `Gl` backend!
    For more info, see the following issue on GitHub:
    https://github.com/PistonDevelopers/opengl_graphics/issues/103
";

/// Contains OpenGL data.
pub struct GlGraphics {
    colored: Colored,
    textured: Textured,
    // Keeps track of the current shader program.
    current_program: Option<GLuint>,
}

impl<'a> GlGraphics {
    /// Creates a new OpenGL back-end.
    ///
    /// # Panics
    /// If the OpenGL function pointers have not been loaded yet.
    /// See https://github.com/PistonDevelopers/opengl_graphics/issues/103 for more info.
    pub fn new(opengl: opengl::OpenGL) -> GlGraphics {
        assert!(gl::Enable::is_loaded(), GL_FUNC_NOT_LOADED);

        let glsl = opengl.to_GLSL();
        // Load the vertices, color and texture coord buffers.
        GlGraphics {
            colored: Colored::new(glsl),
            textured: Textured::new(glsl),
            current_program: None,
       }
    }

    /// Sets viewport with normalized coordinates and center as origin.
    pub fn viewport(
        &mut self,
        x: i32,
        y: i32,
        w: i32,
        h: i32
    ) {
        unsafe {
            gl::Viewport(x as GLint, y as GLint, w as GLsizei, h as GLsizei);
        }
    }

    /// Sets the current program only if the program is not in use.
    pub fn use_program(&mut self, program: GLuint) {
        match self.current_program {
            None => {},
            Some(current_program) => {
                if program == current_program { return; }
            },
        }

        unsafe {
            gl::UseProgram(program);
        }
        self.current_program = Some(program);
    }

    /// Unset the current program.
    ///
    /// This forces the current program to be set on next drawing call.
    pub fn clear_program(&mut self) {
        self.current_program = None
    }

    /// Draws graphics.
    pub fn draw<F>(&mut self, viewport: [i32; 4], f: F)
        where
            F: FnOnce(Context, &mut GlGraphics)
    {
        let [x, y, w, h] = viewport;
        self.viewport(x, y, w, h);
        self.clear_program();
        self.enable_alpha_blend();
        let c = Context::abs(
            w as f64,
            h as f64
        );
        f(c, self);
        self.disable_alpha_blend();
    }

    /// Assume all textures has alpha channel for now.
    pub fn has_texture_alpha(&self, _texture: &Texture) -> bool { true }

    /// Enabled alpha blending.
    pub fn enable_alpha_blend(&mut self) {
        unsafe {
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        }
    }

    /// Disables alpha blending.
    pub fn disable_alpha_blend(&mut self) {
        unsafe {
            gl::Disable(gl::BLEND);
        }
    }
}

impl Graphics for GlGraphics {
    type Texture = Texture;

    fn clear(&mut self, color: [f32; 4]) {
        unsafe {
            let [r, g, b, a] = color;
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
    }

    fn tri_list<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.colored.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.colored;

        unsafe {
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
        }

        f(&mut |vertices: &[f32]| {
            // xy makes two floats.
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }

    fn tri_list_uv<F>(
        &mut self,
        _draw_state: &DrawState,
        color: &[f32; 4],
        texture: &Texture,
        mut f: F
    )
        where F: FnMut(&mut FnMut(&[f32], &[f32]))
    {
        {
            // Set shader program.
            let shader_program = self.textured.program;
            self.use_program(shader_program);
        }
        let ref mut shader = self.textured;

        let texture = texture.get_id();
        unsafe {
            gl::BindTexture(gl::TEXTURE_2D, texture);
            // Render triangles whether they are facing
            // clockwise or counter clockwise.
            gl::Disable(gl::CULL_FACE);
            gl::BindVertexArray(shader.vao);
            gl::Uniform4f(shader.color, color[0], color[1], color[2], color[3]);
        }

        f(&mut |vertices: &[f32], texture_coords: &[f32]| {
            let size_vertices: i32 = 2;
            let items: i32 = vertices.len() as i32 / size_vertices;

            unsafe {
                shader.pos.set(vertices);
                shader.uv.set(texture_coords);
                gl::DrawArrays(gl::TRIANGLES, 0, items);
            }
        });

        unsafe {
            gl::BindVertexArray(0);
        }
    }
}

// Might not fail if previous tests loaded functions.
#[test]
#[should_fail]
fn test_gl_loaded() {
    GlGraphics::new(opengl::OpenGL::_3_2);
}
<|endoftext|>


<commit_before>
//! Glyph caching

use error::Error;
use freetype::ffi;
use freetype;
use freetype::error::Error::MissingFontField;
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use graphics;

use Texture;

pub type FontSize = u32;

pub type Character = graphics::character::Character<Texture>;

/// A struct used for caching rendered font.
pub struct GlyphCache {
    /// The font face.
    pub face: freetype::Face,
    data: HashMap<FontSize, HashMap<char, Character>>,
}

impl GlyphCache {

    /// Constructor for a GlyphCache.
    pub fn new(font: &Path) -> Result<GlyphCache, Error> {
        let freetype = match freetype::Library::init() {
            Ok(freetype) => freetype,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        let font_str = match font.as_str() {
            Some(font_str) => font_str,
            None => return Err(Error::FreetypeError(MissingFontField)),
        };
        let face = match freetype.new_face(font_str, 0) {
            Ok(face) => face,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
        })
    }

    /// Load a `Character` from a given `FontSize` and `char`.
    fn load_character(&mut self, size: FontSize, ch: char) {
        self.face.set_pixel_sizes(0, size).unwrap();
        self.face.load_char(ch as ffi::FT_ULong, freetype::face::DEFAULT).unwrap();
        let glyph = self.face.glyph().get_glyph().unwrap();
        let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None)
            .unwrap();
        let bitmap = bitmap_glyph.bitmap();
        let texture = Texture::from_memory_alpha(bitmap.buffer(),
                                                 bitmap.width() as u32,
                                                 bitmap.rows() as u32).unwrap();
        let glyph_size = glyph.advance();
        self.data[size].insert(ch, Character {
            offset: [
                    bitmap_glyph.left() as f64,
                    bitmap_glyph.top() as f64
                ],
            size: [
                    (glyph_size.x >> 16) as f64,
                    (glyph_size.y >> 16) as f64
                ],
            texture: texture,
        });
    }

}

impl graphics::character::CharacterCache<Texture> for GlyphCache {
    fn character(&mut self, size: FontSize, ch: char) -> &Character {
        match {
            match self.data.entry(size) {
                Vacant(entry) => entry.set(HashMap::new()),
                Occupied(entry) => entry.into_mut(),
            }
        }.contains_key(&ch) {
            true => &self.data[size][ch],
            false => { self.load_character(size, ch); &self.data[size][ch] }
        }
    }
}

<commit_msg>Fixed compilation error: added documentation to type aliases.<commit_after>
//! Glyph caching

use error::Error;
use freetype::ffi;
use freetype;
use freetype::error::Error::MissingFontField;
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use graphics;

use Texture;

/// The type alias for the font size.
pub type FontSize = u32;

/// The type alias for font characters.
pub type Character = graphics::character::Character<Texture>;

/// A struct used for caching rendered font.
pub struct GlyphCache {
    /// The font face.
    pub face: freetype::Face,
    data: HashMap<FontSize, HashMap<char, Character>>,
}

impl GlyphCache {

    /// Constructor for a GlyphCache.
    pub fn new(font: &Path) -> Result<GlyphCache, Error> {
        let freetype = match freetype::Library::init() {
            Ok(freetype) => freetype,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        let font_str = match font.as_str() {
            Some(font_str) => font_str,
            None => return Err(Error::FreetypeError(MissingFontField)),
        };
        let face = match freetype.new_face(font_str, 0) {
            Ok(face) => face,
            Err(why) => return Err(Error::FreetypeError(why)),
        };
        Ok(GlyphCache {
            face: face,
            data: HashMap::new(),
        })
    }

    /// Load a `Character` from a given `FontSize` and `char`.
    fn load_character(&mut self, size: FontSize, ch: char) {
        self.face.set_pixel_sizes(0, size).unwrap();
        self.face.load_char(ch as ffi::FT_ULong, freetype::face::DEFAULT).unwrap();
        let glyph = self.face.glyph().get_glyph().unwrap();
        let bitmap_glyph = glyph.to_bitmap(freetype::render_mode::RenderMode::Normal, None)
            .unwrap();
        let bitmap = bitmap_glyph.bitmap();
        let texture = Texture::from_memory_alpha(bitmap.buffer(),
                                                 bitmap.width() as u32,
                                                 bitmap.rows() as u32).unwrap();
        let glyph_size = glyph.advance();
        self.data[size].insert(ch, Character {
            offset: [
                    bitmap_glyph.left() as f64,
                    bitmap_glyph.top() as f64
                ],
            size: [
                    (glyph_size.x >> 16) as f64,
                    (glyph_size.y >> 16) as f64
                ],
            texture: texture,
        });
    }

}

impl graphics::character::CharacterCache<Texture> for GlyphCache {
    fn character(&mut self, size: FontSize, ch: char) -> &Character {
        match {
            match self.data.entry(size) {
                Vacant(entry) => entry.set(HashMap::new()),
                Occupied(entry) => entry.into_mut(),
            }
        }.contains_key(&ch) {
            true => &self.data[size][ch],
            false => { self.load_character(size, ch); &self.data[size][ch] }
        }
    }
}

<|endoftext|>


<commit_before>use std::io::{Listener, Acceptor};
use std::io::net::tcp::{TcpListener, TcpStream};

static EXT_PORT: u16 = 8443;
static SSH_PORT: u16 = 22;
static SSL_PORT: u16 = 9443;

fn keep_copying(mut a: TcpStream, mut b: TcpStream) {
	let mut buf = [0u8,..1024];
	loop {
		let read = match a.read(buf) {
			Err(..) => { drop(a); return; },
			Ok(r) => r
		};
		match b.write(buf.slice_to(read)) {
			Err(..) => { drop(a); return; },
			Ok(..) => ()
		};
	}
}

fn start_pipe(front: TcpStream, port: u16, header: Option<u8>) {
	let mut back = match TcpStream::connect("127.0.0.1", port) {
		Err(e) => {
			println!("Error connecting: {}", e);
			drop(front);
			return;
		},
		Ok(b) => b
	};
	if header.is_some() {
		match back.write_u8(header.unwrap()) {
			Err(e) => {
				println!("Error writing first byte: {}", e);
				drop(back);
				drop(front);
				return;
			},
			Ok(..) => ()
		}
	}
	let front_copy = front.clone();
	let back_copy = back.clone();

	spawn(proc() {
		keep_copying(front, back);
	});
	spawn(proc() {
		keep_copying(back_copy, front_copy);
	});
}

fn handle_new_connection(mut stream: TcpStream) {
	let header: Option<u8> = match stream.read_byte() {
		Err(..) => None,
		Ok(b) => Some(b)
	};
	if header.is_some() && (header.unwrap() == 22 || header.unwrap() == 128) {
		start_pipe(stream, SSL_PORT, header);
	}
	else {
		start_pipe(stream, SSH_PORT, header);
	}
}

fn main() {
    let mut acceptor = TcpListener::bind("127.0.0.1", EXT_PORT).listen().unwrap();
    println!("listening started, ready to accept");
    for stream in acceptor.incoming() {
		match stream {
			Err(e) => println!("Strange connection broken: {}", e),
			Ok(stream) => spawn(proc() {
					// connection succeeded
					handle_new_connection(stream);
					})
		}
    }
	drop(acceptor);
}
<commit_msg>Moving to newer version of the api and added support for timeouts<commit_after>use std::io::{Listener, Acceptor,IoError, IoErrorKind};
use std::io::net::tcp::{TcpListener, TcpStream};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

static EXT_PORT: u16 = 8443;
static SSH_PORT: u16 = 22;
static SSL_PORT: u16 = 9443;

fn keep_copying(mut a: TcpStream, mut b: TcpStream, timedOut: Arc<AtomicBool>) {
	a.set_read_timeout(Some(15*60*1000));
	let mut buf = [0u8,..1024];
	loop {
		let read = match a.read(&mut buf) {
			Err(ref err) => {
				let other = timedOut.swap(true, Ordering::AcqRel);
				if other {
					// the other side also timed-out / errored, so lets go
					drop(a);
					drop(b);
					return;
				}
				if err.kind == IoErrorKind::TimedOut {
					continue;
				}
				// normal errors, just stop
				drop(a);
				drop(b);
				return; // normal errors, stop
			},
			Ok(r) => r
		};
		timedOut.store(false, Ordering::Release);
		match b.write(buf.slice_to(read)) {
			Err(..) => {
				timedOut.store(true, Ordering::Release);
				drop(a);
				drop(b);
				return;
			},
			Ok(..) => ()
		};
	}
}

fn start_pipe(front: TcpStream, port: u16, header: Option<u8>) {
	let mut back = match TcpStream::connect(("127.0.0.1", port)) {
		Err(e) => {
			println!("Error connecting: {}", e);
			drop(front);
			return;
		},
		Ok(b) => b
	};
	if header.is_some() {
		match back.write_u8(header.unwrap()) {
			Err(e) => {
				println!("Error writing first byte: {}", e);
				drop(back);
				drop(front);
				return;
			},
			Ok(..) => ()
		}
	}
	let front_copy = front.clone();
	let back_copy = back.clone();

	let timedOut = Arc::new(AtomicBool::new(false));
	let timedOut_copy = timedOut.clone();

	spawn(move|| {
		keep_copying(front, back, timedOut);
	});
	spawn(move|| {
		keep_copying(back_copy, front_copy, timedOut_copy);
	});
}

fn handle_new_connection(mut stream: TcpStream) {
	stream.set_read_timeout(Some(3000));
	let header: Option<u8> = match stream.read_byte() {
		Err(..) => None,
		Ok(b) => Some(b)
	};
	if header.is_some() && (header.unwrap() == 22 || header.unwrap() == 128) {
		start_pipe(stream, SSL_PORT, header);
	}
	else {
		start_pipe(stream, SSH_PORT, header);
	}
}

fn main() {
    let mut acceptor = TcpListener::bind(("127.0.0.1", EXT_PORT)).listen().unwrap();
    println!("listening started, ready to accept");
    for stream in acceptor.incoming() {
		match stream {
			Err(e) => println!("Strange connection broken: {}", e),
			Ok(stream) => spawn(move|| {
					// connection succeeded
					handle_new_connection(stream);
					})
		}
    }
	drop(acceptor);
}
<|endoftext|>