<commit_before>/*
 * Copyright (c) 2015-2017 the original author or authors.
 *
 * 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.
 */

use common::run_java;

mod common;

#[test]
fn basic() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "", &[], &["Resource exhaustion event: the JVM was unable to create a thread.",
        "ERROR: PoolStats action failed: cannot determine memory usage statistics since the JVM is unable to create a thread"]));
}

#[test]
fn print_memory_usage_0() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "=printMemoryUsage=0", &[], &["jvmkill killing current process"]));
}

#[test]
fn time_10_count_2() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "=time=10,count=2,printHeapHistogram=1,heapHistogramMaxEntries=10,printMemoryUsage=0",
                      &["Ljava/lang/Class;"], &["ResourceExhausted! (1/2)"]));
}

#[test]
fn parallel_time_10_count_2() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ParallelThreadExhaustion", "=time=10,count=2", &[],
                      &["ResourceExhausted! (1/2)", "jvmkill killing current process"]));
}
<commit_msg>Improve test stability<commit_after>/*
 * Copyright (c) 2015-2017 the original author or authors.
 *
 * 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.
 */

use common::run_java;

mod common;

#[test]
fn basic() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "", &[], &["Resource exhaustion event: the JVM was unable to create a thread.",
        "ERROR: PoolStats action failed: cannot determine memory usage statistics since the JVM is unable to create a thread"]));
}

#[test]
fn print_memory_usage_0() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "=printMemoryUsage=0", &[], &["jvmkill killing current process"]));
}

#[test]
fn time_10_count_2() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ThreadExhaustion", "=time=10,count=2,printHeapHistogram=1,heapHistogramMaxEntries=10,printMemoryUsage=0",
                      &[], &["ResourceExhausted! (1/2)", "jvmkill killing current process"]));
}

#[test]
fn parallel_time_10_count_2() {
    assert!(!run_java("org.cloudfoundry.jvmkill.ParallelThreadExhaustion", "=time=10,count=2", &[],
                      &["ResourceExhausted! (1/2)", "jvmkill killing current process"]));
}
<|endoftext|>


<commit_before>/// OData query parameters
///
/// ## Example
///
/// ```rust
/// use shapir::odata::Parameters;
///
///	let opts = Parameters::new()
///		.select(Some(vec!["Field1", "Field2", "3"]))
///		.expand(Some(vec!["Children", "Siblings"]))
///		.filter(Some(vec!["A eq B", "true"]))
///		.order_by(Some(vec!["Date asc", "Time desc", "Id"]))
///		.top(Some(10u32))
///		.skip(Some(9u32));
/// ```
///

#[derive(Debug, Clone, Default)]
pub struct Parameters {
	select: Option<Vec<String>>,
	expand: Option<Vec<String>>,
	filter: Option<Vec<String>>,
	order_by: Option<Vec<String>>,
	top: Option<u32>,
	skip: Option<u32>,
}

impl Parameters {
	/// Create a new instance of `Parameters` with no options specified.
	pub fn new() -> Self {
		Parameters {
			select: None,
			expand: None,
			filter: None,
			order_by: None,
			top: None,
			skip: None,
		}
	}

	/// Set `$select` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theselectsystemqueryoption)
	/// for more details.
	pub fn select<T>(mut self, opt: Option<T>) -> Self where T: IntoIterator, T::Item: Into<String> {
		match opt {
			Some(items) => {
				let items = items.into_iter()
					.map(|v| v.into())
					.collect();
				self.select = Some(items);
			},
			None => {
				self.select = None;
			},
		};

		self
	}

	/// Set `$expand` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theexpandsystemqueryoption)
	/// for more details.
	pub fn expand<T>(mut self, opt: Option<T>) -> Self where T: IntoIterator, T::Item: Into<String> {
		match opt {
			Some(items) => {
				let items = items.into_iter()
					.map(|v| v.into())
					.collect();
				self.expand = Some(items);
			},
			None => {
				self.expand = None;
			},
		};

		self
	}

	/// Set `$filter` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thefiltersystemqueryoption)
	/// for more details.
	pub fn filter<T>(mut self, opt: Option<T>) -> Self where T: IntoIterator, T::Item: Into<String> {
		match opt {
			Some(items) => {
				let items = items.into_iter()
					.map(|v| v.into())
					.collect();
				self.filter = Some(items);
			},
			None => {
				self.filter = None;
			},
		};

		self
	}

	/// Set `$orderBy` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theorderbysystemqueryoption)
	/// for more details.
	pub fn order_by<T>(mut self, opt: Option<T>) -> Self where T: IntoIterator, T::Item: Into<String> {
		match opt {
			Some(items) => {
				let items = items.into_iter()
					.map(|v| v.into())
					.collect();
				self.order_by = Some(items);
			},
			None => {
				self.order_by = None;
			},
		};

		self
	}

	/// Set `$top` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thetopsystemqueryoption)
	/// for more details.
	pub fn top<T>(mut self, opt: Option<T>) -> Self where T: Into<u32> {
		match opt {
			Some(amount) => {
				self.top = Some(amount.into());
			},
			None => {
				self.top = None;
			},
		};

		self
	}

	/// Set `$skip` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theskipsystemqueryoption)
	/// for more details.
	pub fn skip<T>(mut self, opt: Option<T>) -> Self where T: Into<u32> {
		match opt {
			Some(amount) => {
				self.skip = Some(amount.into());
			},
			None => {
				self.skip = None;
			},
		};

		self
	}
}

impl Into<String> for Parameters {
	fn into(self) -> String {
		use url::form_urlencoded;

		// Fill in options
		let mut options: Vec<(&str, String)> = Vec::new();

		if let Some(items) = self.select {
			options.push(("$select", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.expand {
			options.push(("$expand", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.filter {
			options.push(("$filter", items.into_boxed_slice().join(" and ")));
		};

		if let Some(items) = self.order_by {
			options.push(("$orderBy", items.into_boxed_slice().join(",")));
		};

		if let Some(num) = self.top {
			options.push(("$top", num.to_string()));
		};

		if let Some(num) = self.skip {
			options.push(("$skip", num.to_string()));
		};

		// Convert OData options into URL query
		form_urlencoded::serialize(options)
	}
}

impl ToString for Parameters {
	fn to_string(&self) -> String {
		self.clone().into()
	}
}

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

	fn encode_pairs(v: Vec<(&str, &str)>) -> String {
		use url::form_urlencoded;
		form_urlencoded::serialize(v)
	}

	#[test]
	fn query_options_none() {
		let opts: String = Parameters::new()
			.into();
		assert_eq!(opts, "".to_string());
	}

	#[test]
	fn query_options_select() {
		let opts: String = Parameters::new()
			.select(Some(vec!["Field1", "Field2", "3"]))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$select", "Field1,Field2,3")]));
	}

	#[test]
	fn query_options_expand() {
		let opts: String = Parameters::new()
			.expand(Some(vec!["Children", "Siblings"]))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$expand", "Children,Siblings")]));
	}

	#[test]
	fn query_options_filter() {
		let opts: String = Parameters::new()
			.filter(Some(vec!["A eq B", "true"]))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$filter", "A eq B and true")]));
	}

	#[test]
	fn query_options_order_by() {
		let opts: String = Parameters::new()
			.order_by(Some(vec!["Date asc", "Time desc", "Id"]))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$orderBy", "Date asc,Time desc,Id")]));
	}

	#[test]
	fn query_options_top() {
		let opts: String = Parameters::new()
			.top(Some(10u32))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$top", "10")]));
	}

	#[test]
	fn query_options_skip() {
		let opts: String = Parameters::new()
			.skip(Some(9u32))
			.into();
		assert_eq!(opts, encode_pairs(vec![("$skip", "9")]));
	}

	#[test]
	fn query_options_all() {
		let opts: String = Parameters::new()
			.select(Some(vec!["Field1", "Field2", "3"]))
			.expand(Some(vec!["Children", "Siblings"]))
			.filter(Some(vec!["A eq B", "true"]))
			.order_by(Some(vec!["Date asc", "Time desc", "Id"]))
			.top(Some(10u32))
			.skip(Some(9u32))
			.into();

		let should_be = encode_pairs(vec![
				("$select", "Field1,Field2,3"),
				("$expand", "Children,Siblings"),
				("$filter", "A eq B and true"),
				("$orderBy", "Date asc,Time desc,Id"),
				("$top", "10"),
				("$skip", "9")
			]);

		assert_eq!(opts, should_be);
	}
}
<commit_msg>Add custom parameters and refactor the interface<commit_after>/// OData query parameters
///
/// ## Example
///
/// ```rust
/// use shapir::odata::Parameters;
///
///	let opts = Parameters::new()
///		.select(vec!["Field1", "Field2", "3"])
///		.expand(vec!["Children", "Siblings"])
///		.filter(vec!["A eq B", "true"])
///		.order_by(vec!["Date asc", "Time desc", "Id"])
///		.top(10u32)
///		.skip(9u32);
/// ```
///

#[derive(Debug, Clone, Default)]
pub struct Parameters {
	custom: Option<Vec<(&'static str, String)>>,
	select: Option<Vec<String>>,
	expand: Option<Vec<String>>,
	filter: Option<Vec<String>>,
	order_by: Option<Vec<String>>,
	top: Option<u32>,
	skip: Option<u32>,
}

impl Parameters {
	/// Create a new instance of `Parameters` with no options specified.
	pub fn new() -> Self {
		Parameters {
			custom: None,
			select: None,
			expand: None,
			filter: None,
			order_by: None,
			top: None,
			skip: None,
		}
	}

	/// Set custom parameters
	pub fn custom<V>(mut self, opt: Vec<(&'static str, V)>) -> Self where V: Into<String> {
		let items = opt.into_iter()
			.map(|v| (v.0, v.1.into()))
			.collect();
		self.custom = Some(items);
		self
	}

	/// Add custom parameters
	pub fn custom_add<V>(mut self, param: (&'static str, V)) -> Self where V: Into<String> {
		match self.custom {
			Some(ref mut items) => {
				items.push((param.0, param.1.into()));
			},
			None => {
				self.custom = Some(vec![(param.0, param.1.into())]);
			}
		};

		self
	}

	/// Set `$select` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theselectsystemqueryoption)
	/// for more details.
	pub fn select<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.select = Some(items);
		self
	}

	/// Set `$expand` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theexpandsystemqueryoption)
	/// for more details.
	pub fn expand<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.expand = Some(items);
		self
	}

	/// Set `$filter` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thefiltersystemqueryoption)
	/// for more details.
	pub fn filter<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.filter = Some(items);
		self
	}

	/// Set `$orderBy` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theorderbysystemqueryoption)
	/// for more details.
	pub fn order_by<T>(mut self, opt: T) -> Self where T: IntoIterator, T::Item: Into<String> {
		let items = opt.into_iter()
			.map(|v| v.into())
			.collect();
		self.order_by = Some(items);
		self
	}

	/// Set `$top` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#thetopsystemqueryoption)
	/// for more details.
	pub fn top<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.top = Some(opt.into());
		self
	}

	/// Set `$skip` option. See [OData documentation](http://www.odata.org/documentation/odata-version-3-0/odata-version-3-0-core-protocol/#theskipsystemqueryoption)
	/// for more details.
	pub fn skip<T>(mut self, opt: T) -> Self where T: Into<u32> {
		self.skip = Some(opt.into());
		self
	}
}

impl Into<String> for Parameters {
	fn into(self) -> String {
		use url::form_urlencoded;

		// Fill in options
		let mut options: Vec<(&str, String)> = Vec::new();

		if let Some(items) = self.custom {
			options.extend(items);
		};

		if let Some(items) = self.select {
			options.push(("$select", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.expand {
			options.push(("$expand", items.into_boxed_slice().join(",")));
		};

		if let Some(items) = self.filter {
			options.push(("$filter", items.into_boxed_slice().join(" and ")));
		};

		if let Some(items) = self.order_by {
			options.push(("$orderBy", items.into_boxed_slice().join(",")));
		};

		if let Some(num) = self.top {
			options.push(("$top", num.to_string()));
		};

		if let Some(num) = self.skip {
			options.push(("$skip", num.to_string()));
		};

		// Convert OData options into URL query
		form_urlencoded::serialize(options)
	}
}

impl ToString for Parameters {
	fn to_string(&self) -> String {
		self.clone().into()
	}
}

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

	fn encode_pairs(v: Vec<(&str, &str)>) -> String {
		use url::form_urlencoded;
		form_urlencoded::serialize(v)
	}

	#[test]
	fn query_options_none() {
		let opts: String = Parameters::new()
			.into();
		assert_eq!(opts, "".to_string());
	}

	#[test]
	fn query_options_custom() {
		let opts: String = Parameters::new()
			.custom(vec![("a", "hello"), ("enable", "true")])
			.custom_add(("price", "20"))
			.into();
		assert_eq!(opts, encode_pairs(vec![("a", "hello"), ("enable", "true"), ("price", "20")]));
	}

	#[test]
	fn query_options_select() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2", "3"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$select", "Field1,Field2,3")]));
	}

	#[test]
	fn query_options_expand() {
		let opts: String = Parameters::new()
			.expand(vec!["Children", "Siblings"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$expand", "Children,Siblings")]));
	}

	#[test]
	fn query_options_filter() {
		let opts: String = Parameters::new()
			.filter(vec!["A eq B", "true"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$filter", "A eq B and true")]));
	}

	#[test]
	fn query_options_order_by() {
		let opts: String = Parameters::new()
			.order_by(vec!["Date asc", "Time desc", "Id"])
			.into();
		assert_eq!(opts, encode_pairs(vec![("$orderBy", "Date asc,Time desc,Id")]));
	}

	#[test]
	fn query_options_top() {
		let opts: String = Parameters::new()
			.top(10u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$top", "10")]));
	}

	#[test]
	fn query_options_skip() {
		let opts: String = Parameters::new()
			.skip(9u32)
			.into();
		assert_eq!(opts, encode_pairs(vec![("$skip", "9")]));
	}

	#[test]
	fn query_options_all() {
		let opts: String = Parameters::new()
			.select(vec!["Field1", "Field2", "3"])
			.expand(vec!["Children", "Siblings"])
			.filter(vec!["A eq B", "true"])
			.order_by(vec!["Date asc", "Time desc", "Id"])
			.top(10u32)
			.skip(9u32)
			.into();

		let should_be = encode_pairs(vec![
				("$select", "Field1,Field2,3"),
				("$expand", "Children,Siblings"),
				("$filter", "A eq B and true"),
				("$orderBy", "Date asc,Time desc,Id"),
				("$top", "10"),
				("$skip", "9")
			]);

		assert_eq!(opts, should_be);
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 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.

use std::collections::HashMap;
use std::env;
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::path::PathBuf;
use std::str::FromStr;
use std::vec::IntoIter;

use error::{Error, Result};
use package::PackageIdent;

#[cfg(not(windows))]
const ENV_PATH_SEPARATOR: char = ':';

#[cfg(windows)]
const ENV_PATH_SEPARATOR: char = ';';

pub fn parse_key_value(s: &str) -> Result<HashMap<String, String>> {
    Ok(HashMap::from_iter(
        s.lines()
            .map(|l| l.splitn(2, '=').collect::<Vec<_>>())
            .map(|kv| (kv[0].to_string(), kv[1].to_string())),
    ))
}

#[derive(Debug)]
pub struct Bind {
    pub service: String,
    pub exports: Vec<String>,
}

impl FromStr for Bind {
    type Err = Error;

    fn from_str(line: &str) -> Result<Self> {
        let mut parts = line.split('=');
        let service = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(service) => service.to_string(),
        };
        let exports = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(exports) => exports.split(' ').map(|t| t.to_string()).collect(),
        };
        Ok(Bind {
            service: service,
            exports: exports,
        })
    }
}

impl fmt::Display for Bind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let formatted_exports = self.exports.join(" ");
        write!(f, "[{}]={}", self.service, formatted_exports)
    }
}

/// Describes a bind mapping in a composite package.
#[derive(Debug, PartialEq)]
pub struct BindMapping {
    /// The name of the bind of a given service.
    pub bind_name: String,
    /// The identifier of the service within the composite package
    /// that should satisfy the named bind.
    pub satisfying_service: PackageIdent,
}

impl FromStr for BindMapping {
    type Err = Error;

    fn from_str(line: &str) -> Result<Self> {
        let mut parts = line.split(':');
        let bind_name = parts
            .next()
            .and_then(|bn| Some(bn.to_string()))
            .ok_or(Error::MetaFileBadBind)?;
        let satisfying_service = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(satisfying_service) => satisfying_service.parse()?,
        };
        Ok(BindMapping {
            bind_name: bind_name,
            satisfying_service: satisfying_service,
        })
    }
}

#[derive(Debug, PartialEq)]
pub struct EnvVar {
    pub key: String,
    pub value: String,
    pub separator: Option<char>,
}

#[derive(Debug)]
pub struct PkgEnv {
    inner: Vec<EnvVar>,
}

impl PkgEnv {
    pub fn new(values: HashMap<String, String>, separators: HashMap<String, String>) -> Self {
        Self {
            inner: values
                .into_iter()
                .map(|(key, value)| {
                    if let Some(sep) = separators.get(&key) {
                        EnvVar {
                            key: key,
                            value: value,
                            separator: sep.to_owned().pop(),
                        }
                    } else {
                        EnvVar {
                            key: key,
                            value: value,
                            separator: None,
                        }
                    }
                })
                .collect(),
        }
    }

    pub fn from_paths(paths: Vec<PathBuf>) -> Self {
        let p = env::join_paths(&paths).expect("Failed to build path string");
        Self {
            inner: vec![
                EnvVar {
                    key: "PATH".to_string(),
                    value: p.into_string()
                        .expect("Failed to convert path to utf8 string"),
                    separator: Some(ENV_PATH_SEPARATOR),
                },
            ],
        }
    }

    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }
}

impl IntoIterator for PkgEnv {
    type Item = EnvVar;
    type IntoIter = IntoIter<EnvVar>;

    fn into_iter(self) -> Self::IntoIter {
        self.inner.into_iter()
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum MetaFile {
    BindMap, // Composite-only
    Binds,
    BindsOptional,
    CFlags,
    Config,
    Deps,
    Environment,
    EnvironmentSep,
    Exports,
    Exposes,
    Ident,
    LdFlags,
    LdRunPath,
    Manifest,
    Path,
    ResolvedServices, // Composite-only
    RuntimeEnvironment,
    RuntimePath,
    Services, // Composite-only
    SvcGroup,
    SvcUser,
    Target,
    TDeps,
    Type,
}

impl fmt::Display for MetaFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = match *self {
            MetaFile::BindMap => "BIND_MAP",
            MetaFile::Binds => "BINDS",
            MetaFile::BindsOptional => "BINDS_OPTIONAL",
            MetaFile::CFlags => "CFLAGS",
            MetaFile::Config => "default.toml",
            MetaFile::Deps => "DEPS",
            MetaFile::Environment => "ENVIRONMENT",
            MetaFile::EnvironmentSep => "ENVIRONMENT_SEP",
            MetaFile::Exports => "EXPORTS",
            MetaFile::Exposes => "EXPOSES",
            MetaFile::Ident => "IDENT",
            MetaFile::LdFlags => "LDFLAGS",
            MetaFile::LdRunPath => "LD_RUN_PATH",
            MetaFile::Manifest => "MANIFEST",
            MetaFile::Path => "PATH",
            MetaFile::ResolvedServices => "RESOLVED_SERVICES",
            MetaFile::RuntimeEnvironment => "RUNTIME_ENVIRONMENT",
            MetaFile::RuntimePath => "RUNTIME_PATH",
            MetaFile::Services => "SERVICES",
            MetaFile::SvcGroup => "SVC_GROUP",
            MetaFile::SvcUser => "SVC_USER",
            MetaFile::Target => "TARGET",
            MetaFile::TDeps => "TDEPS",
            MetaFile::Type => "TYPE",
        };
        write!(f, "{}", id)
    }
}

pub enum PackageType {
    Standalone,
    Composite,
}

impl fmt::Display for PackageType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = match *self {
            PackageType::Standalone => "Standalone",
            PackageType::Composite => "Composite",
        };
        write!(f, "{}", id)
    }
}

impl FromStr for PackageType {
    type Err = Error;

    fn from_str(value: &str) -> Result<Self> {
        match value.as_ref() {
            "standalone" => Ok(PackageType::Standalone),
            "composite" => Ok(PackageType::Composite),
            _ => Err(Error::InvalidPackageType(value.to_string())),
        }
    }
}

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

    static ENVIRONMENT: &str = r#"PATH=/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin
PYTHONPATH=/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages
"#;
    static ENVIRONMENT_SEP: &str = r#"PATH=:
PYTHONPATH=:
"#;
    static EXPORTS: &str = r#"status-port=status.port
port=front-end.port
"#;
    static PATH: &str = "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin";

    #[test]
    #[should_panic]
    fn malformed_file() {
        parse_key_value(&"PATH").unwrap();
    }

    #[test]
    fn can_parse_environment_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert(
            "PATH".to_string(),
            "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
        );
        m.insert(
            "PYTHONPATH".to_string(),
            "/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages"
                .to_string(),
        );

        assert_eq!(parse_key_value(&ENVIRONMENT).unwrap(), m);
    }

    #[test]
    fn can_parse_environment_sep_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert("PATH".to_string(), ":".to_string());
        m.insert("PYTHONPATH".to_string(), ":".to_string());

        assert_eq!(parse_key_value(&ENVIRONMENT_SEP).unwrap(), m);
    }

    #[test]
    fn can_parse_exports_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert("status-port".to_string(), "status.port".to_string());
        m.insert("port".to_string(), "front-end.port".to_string());

        assert_eq!(parse_key_value(&EXPORTS).unwrap(), m);
    }

    #[test]
    fn build_pkg_env() {
        let mut result = PkgEnv::new(
            parse_key_value(&ENVIRONMENT).unwrap(),
            parse_key_value(&ENVIRONMENT_SEP).unwrap(),
        ).into_iter()
            .collect::<Vec<_>>();
        // Sort the result by key, so we have a guarantee of order
        result.sort_by_key(|v| v.key.to_owned());

        let expected = vec![
            EnvVar {
                key: "PATH".to_string(),
                value: "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
                separator: Some(':'),
            },
            EnvVar {
                key: "PYTHONPATH".to_string(),
                value:
                    "/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages"
                        .to_string(),
                separator: Some(':'),
            },
        ];

        assert_eq!(result, expected);
    }

    #[test]
    fn build_pkg_env_is_empty() {
        let result = PkgEnv::new(HashMap::new(), HashMap::new());
        assert!(result.is_empty());
    }

    #[test]
    fn build_pkg_env_from_path() {
        let result = PkgEnv::from_paths(vec![PathBuf::from(PATH)])
            .into_iter()
            .collect::<Vec<_>>();

        let expected = vec![
            EnvVar {
                key: "PATH".to_string(),
                value: "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
                separator: Some(ENV_PATH_SEPARATOR),
            },
        ];

        assert_eq!(result, expected);
    }

    #[test]
    fn can_parse_a_valid_bind_mapping() {
        let input = "my_bind:core/test";

        let output: BindMapping = input.parse().unwrap();

        assert_eq!(output.bind_name, "my_bind");
        assert_eq!(
            output.satisfying_service,
            PackageIdent::from_str("core/test").unwrap()
        );
    }

    #[test]
    fn fails_to_parse_a_bind_mapping_with_an_invalid_service_identifier() {
        let input = "my_bind:this-is-a-bad-identifier";
        let output = input.parse::<BindMapping>();
        assert!(output.is_err());
    }
}
<commit_msg>Derive Debug and Serialize on the Bind struct<commit_after>// Copyright (c) 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.

use std::collections::HashMap;
use std::env;
use std::fmt;
use std::iter::{FromIterator, IntoIterator};
use std::path::PathBuf;
use std::str::FromStr;
use std::vec::IntoIter;

use error::{Error, Result};
use package::PackageIdent;

#[cfg(not(windows))]
const ENV_PATH_SEPARATOR: char = ':';

#[cfg(windows)]
const ENV_PATH_SEPARATOR: char = ';';

pub fn parse_key_value(s: &str) -> Result<HashMap<String, String>> {
    Ok(HashMap::from_iter(
        s.lines()
            .map(|l| l.splitn(2, '=').collect::<Vec<_>>())
            .map(|kv| (kv[0].to_string(), kv[1].to_string())),
    ))
}

#[derive(Clone, Debug, Serialize)]
pub struct Bind {
    pub service: String,
    pub exports: Vec<String>,
}

impl FromStr for Bind {
    type Err = Error;

    fn from_str(line: &str) -> Result<Self> {
        let mut parts = line.split('=');
        let service = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(service) => service.to_string(),
        };
        let exports = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(exports) => exports.split(' ').map(|t| t.to_string()).collect(),
        };
        Ok(Bind {
            service: service,
            exports: exports,
        })
    }
}

impl fmt::Display for Bind {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let formatted_exports = self.exports.join(" ");
        write!(f, "[{}]={}", self.service, formatted_exports)
    }
}

/// Describes a bind mapping in a composite package.
#[derive(Debug, PartialEq)]
pub struct BindMapping {
    /// The name of the bind of a given service.
    pub bind_name: String,
    /// The identifier of the service within the composite package
    /// that should satisfy the named bind.
    pub satisfying_service: PackageIdent,
}

impl FromStr for BindMapping {
    type Err = Error;

    fn from_str(line: &str) -> Result<Self> {
        let mut parts = line.split(':');
        let bind_name = parts
            .next()
            .and_then(|bn| Some(bn.to_string()))
            .ok_or(Error::MetaFileBadBind)?;
        let satisfying_service = match parts.next() {
            None => return Err(Error::MetaFileBadBind),
            Some(satisfying_service) => satisfying_service.parse()?,
        };
        Ok(BindMapping {
            bind_name: bind_name,
            satisfying_service: satisfying_service,
        })
    }
}

#[derive(Debug, PartialEq)]
pub struct EnvVar {
    pub key: String,
    pub value: String,
    pub separator: Option<char>,
}

#[derive(Debug)]
pub struct PkgEnv {
    inner: Vec<EnvVar>,
}

impl PkgEnv {
    pub fn new(values: HashMap<String, String>, separators: HashMap<String, String>) -> Self {
        Self {
            inner: values
                .into_iter()
                .map(|(key, value)| {
                    if let Some(sep) = separators.get(&key) {
                        EnvVar {
                            key: key,
                            value: value,
                            separator: sep.to_owned().pop(),
                        }
                    } else {
                        EnvVar {
                            key: key,
                            value: value,
                            separator: None,
                        }
                    }
                })
                .collect(),
        }
    }

    pub fn from_paths(paths: Vec<PathBuf>) -> Self {
        let p = env::join_paths(&paths).expect("Failed to build path string");
        Self {
            inner: vec![
                EnvVar {
                    key: "PATH".to_string(),
                    value: p.into_string()
                        .expect("Failed to convert path to utf8 string"),
                    separator: Some(ENV_PATH_SEPARATOR),
                },
            ],
        }
    }

    pub fn is_empty(&self) -> bool {
        self.inner.is_empty()
    }
}

impl IntoIterator for PkgEnv {
    type Item = EnvVar;
    type IntoIter = IntoIter<EnvVar>;

    fn into_iter(self) -> Self::IntoIter {
        self.inner.into_iter()
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum MetaFile {
    BindMap, // Composite-only
    Binds,
    BindsOptional,
    CFlags,
    Config,
    Deps,
    Environment,
    EnvironmentSep,
    Exports,
    Exposes,
    Ident,
    LdFlags,
    LdRunPath,
    Manifest,
    Path,
    ResolvedServices, // Composite-only
    RuntimeEnvironment,
    RuntimePath,
    Services, // Composite-only
    SvcGroup,
    SvcUser,
    Target,
    TDeps,
    Type,
}

impl fmt::Display for MetaFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = match *self {
            MetaFile::BindMap => "BIND_MAP",
            MetaFile::Binds => "BINDS",
            MetaFile::BindsOptional => "BINDS_OPTIONAL",
            MetaFile::CFlags => "CFLAGS",
            MetaFile::Config => "default.toml",
            MetaFile::Deps => "DEPS",
            MetaFile::Environment => "ENVIRONMENT",
            MetaFile::EnvironmentSep => "ENVIRONMENT_SEP",
            MetaFile::Exports => "EXPORTS",
            MetaFile::Exposes => "EXPOSES",
            MetaFile::Ident => "IDENT",
            MetaFile::LdFlags => "LDFLAGS",
            MetaFile::LdRunPath => "LD_RUN_PATH",
            MetaFile::Manifest => "MANIFEST",
            MetaFile::Path => "PATH",
            MetaFile::ResolvedServices => "RESOLVED_SERVICES",
            MetaFile::RuntimeEnvironment => "RUNTIME_ENVIRONMENT",
            MetaFile::RuntimePath => "RUNTIME_PATH",
            MetaFile::Services => "SERVICES",
            MetaFile::SvcGroup => "SVC_GROUP",
            MetaFile::SvcUser => "SVC_USER",
            MetaFile::Target => "TARGET",
            MetaFile::TDeps => "TDEPS",
            MetaFile::Type => "TYPE",
        };
        write!(f, "{}", id)
    }
}

pub enum PackageType {
    Standalone,
    Composite,
}

impl fmt::Display for PackageType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let id = match *self {
            PackageType::Standalone => "Standalone",
            PackageType::Composite => "Composite",
        };
        write!(f, "{}", id)
    }
}

impl FromStr for PackageType {
    type Err = Error;

    fn from_str(value: &str) -> Result<Self> {
        match value.as_ref() {
            "standalone" => Ok(PackageType::Standalone),
            "composite" => Ok(PackageType::Composite),
            _ => Err(Error::InvalidPackageType(value.to_string())),
        }
    }
}

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

    static ENVIRONMENT: &str = r#"PATH=/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin
PYTHONPATH=/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages
"#;
    static ENVIRONMENT_SEP: &str = r#"PATH=:
PYTHONPATH=:
"#;
    static EXPORTS: &str = r#"status-port=status.port
port=front-end.port
"#;
    static PATH: &str = "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin";

    #[test]
    #[should_panic]
    fn malformed_file() {
        parse_key_value(&"PATH").unwrap();
    }

    #[test]
    fn can_parse_environment_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert(
            "PATH".to_string(),
            "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
        );
        m.insert(
            "PYTHONPATH".to_string(),
            "/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages"
                .to_string(),
        );

        assert_eq!(parse_key_value(&ENVIRONMENT).unwrap(), m);
    }

    #[test]
    fn can_parse_environment_sep_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert("PATH".to_string(), ":".to_string());
        m.insert("PYTHONPATH".to_string(), ":".to_string());

        assert_eq!(parse_key_value(&ENVIRONMENT_SEP).unwrap(), m);
    }

    #[test]
    fn can_parse_exports_file() {
        let mut m: HashMap<String, String> = HashMap::new();
        m.insert("status-port".to_string(), "status.port".to_string());
        m.insert("port".to_string(), "front-end.port".to_string());

        assert_eq!(parse_key_value(&EXPORTS).unwrap(), m);
    }

    #[test]
    fn build_pkg_env() {
        let mut result = PkgEnv::new(
            parse_key_value(&ENVIRONMENT).unwrap(),
            parse_key_value(&ENVIRONMENT_SEP).unwrap(),
        ).into_iter()
            .collect::<Vec<_>>();
        // Sort the result by key, so we have a guarantee of order
        result.sort_by_key(|v| v.key.to_owned());

        let expected = vec![
            EnvVar {
                key: "PATH".to_string(),
                value: "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
                separator: Some(':'),
            },
            EnvVar {
                key: "PYTHONPATH".to_string(),
                value:
                    "/hab/pkgs/python/setuptools/35.0.1/20170424072606/lib/python3.6/site-packages"
                        .to_string(),
                separator: Some(':'),
            },
        ];

        assert_eq!(result, expected);
    }

    #[test]
    fn build_pkg_env_is_empty() {
        let result = PkgEnv::new(HashMap::new(), HashMap::new());
        assert!(result.is_empty());
    }

    #[test]
    fn build_pkg_env_from_path() {
        let result = PkgEnv::from_paths(vec![PathBuf::from(PATH)])
            .into_iter()
            .collect::<Vec<_>>();

        let expected = vec![
            EnvVar {
                key: "PATH".to_string(),
                value: "/hab/pkgs/python/setuptools/35.0.1/20170424072606/bin".to_string(),
                separator: Some(ENV_PATH_SEPARATOR),
            },
        ];

        assert_eq!(result, expected);
    }

    #[test]
    fn can_parse_a_valid_bind_mapping() {
        let input = "my_bind:core/test";

        let output: BindMapping = input.parse().unwrap();

        assert_eq!(output.bind_name, "my_bind");
        assert_eq!(
            output.satisfying_service,
            PackageIdent::from_str("core/test").unwrap()
        );
    }

    #[test]
    fn fails_to_parse_a_bind_mapping_with_an_invalid_service_identifier() {
        let input = "my_bind:this-is-a-bad-identifier";
        let output = input.parse::<BindMapping>();
        assert!(output.is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use core::{
    arch::wasm32,
    mem,
    sync::atomic::{AtomicUsize, Ordering},
};
use std::{convert::TryFrom, thread, time::Instant};

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
    parked: AtomicUsize,
}

const UNPARKED: usize = 0;
const PARKED: usize = 1;

impl ThreadParker {
    pub const IS_CHEAP_TO_CONSTRUCT: bool = true;

    #[inline]
    pub fn new() -> ThreadParker {
        ThreadParker {
            parked: AtomicUsize::new(UNPARKED),
        }
    }

    // Prepares the parker. This should be called before adding it to the queue.
    #[inline]
    pub fn prepare_park(&self) {
        self.parked.store(PARKED, Ordering::Relaxed);
    }

    // Checks if the park timed out. This should be called while holding the
    // queue lock after park_until has returned false.
    #[inline]
    pub fn timed_out(&self) -> bool {
        self.parked.load(Ordering::Relaxed) == PARKED
    }

    // Parks the thread until it is unparked. This should be called after it has
    // been added to the queue, after unlocking the queue.
    #[inline]
    pub fn park(&self) {
        while self.parked.load(Ordering::Acquire) == PARKED {
            let val = unsafe {
                wasm32::i32_atomic_wait(
                    ptr(&self.parked),
                    PARKED as i32, // we expect our thread is parked
                    -1,            // wait infinitely
                )
            };
            // we should have either woken up (0) or got a not-equal due to a
            // race (1). We should never time out (2)
            debug_assert!(val == 0 || val == 1);
        }
    }

    // Parks the thread until it is unparked or the timeout is reached. This
    // should be called after it has been added to the queue, after unlocking
    // the queue. Returns true if we were unparked and false if we timed out.
    #[inline]
    pub fn park_until(&self, timeout: Instant) -> bool {
        while self.parked.load(Ordering::Acquire) == PARKED {
            if let Some(left) = timeout.checked_duration_since(Instant::now()) {
                let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value());
                unsafe {
                    wasm32::i32_atomic_wait(ptr(&self.parked), PARKED as i32, nanos_left);
                }
            } else {
                return false;
            }
        }
        true
    }

    // Locks the parker to prevent the target thread from exiting. This is
    // necessary to ensure that thread-local ThreadData objects remain valid.
    // This should be called while holding the queue lock.
    #[inline]
    pub fn unpark_lock(&self) -> UnparkHandle<'_> {
        // We don't need to lock anything, just clear the state
        self.parked.store(UNPARKED, Ordering::Release);
        UnparkHandle(&self.parked)
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle<'a>(&'a AtomicUsize);

impl<'a> UnparkHandle<'a> {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    #[inline]
    pub fn unpark(self) {
        unsafe {
            wasm32::atomic_notify(ptr(self.0), 1);
        }
    }
}

#[inline]
fn ptr(i: &AtomicUsize) -> *mut i32 {
    debug_assert_eq!(mem::size_of::<usize>(), mem::size_of::<i32>());
    i as *const AtomicUsize as *mut isize as *mut i32
}

#[inline]
pub fn thread_yield() {
    thread::yield_now();
}
<commit_msg>Use AtomicI32 and debug_assert more return values<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use core::{
    arch::wasm32,
    sync::atomic::{AtomicI32, Ordering},
};
use std::{convert::TryFrom, thread, time::Instant};

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
    parked: AtomicI32,
}

const UNPARKED: i32 = 0;
const PARKED: i32 = 1;

impl ThreadParker {
    pub const IS_CHEAP_TO_CONSTRUCT: bool = true;

    #[inline]
    pub fn new() -> ThreadParker {
        ThreadParker {
            parked: AtomicI32::new(UNPARKED),
        }
    }

    // Prepares the parker. This should be called before adding it to the queue.
    #[inline]
    pub fn prepare_park(&self) {
        self.parked.store(PARKED, Ordering::Relaxed);
    }

    // Checks if the park timed out. This should be called while holding the
    // queue lock after park_until has returned false.
    #[inline]
    pub fn timed_out(&self) -> bool {
        self.parked.load(Ordering::Relaxed) == PARKED
    }

    // Parks the thread until it is unparked. This should be called after it has
    // been added to the queue, after unlocking the queue.
    #[inline]
    pub fn park(&self) {
        while self.parked.load(Ordering::Acquire) == PARKED {
            let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, -1) };
            // we should have either woken up (0) or got a not-equal due to a
            // race (1). We should never time out (2)
            debug_assert!(r == 0 || r == 1);
        }
    }

    // Parks the thread until it is unparked or the timeout is reached. This
    // should be called after it has been added to the queue, after unlocking
    // the queue. Returns true if we were unparked and false if we timed out.
    #[inline]
    pub fn park_until(&self, timeout: Instant) -> bool {
        while self.parked.load(Ordering::Acquire) == PARKED {
            if let Some(left) = timeout.checked_duration_since(Instant::now()) {
                let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value());
                let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, nanos_left) };
                debug_assert!(r == 0 || r == 1 || r == 2);
            } else {
                return false;
            }
        }
        true
    }

    // Locks the parker to prevent the target thread from exiting. This is
    // necessary to ensure that thread-local ThreadData objects remain valid.
    // This should be called while holding the queue lock.
    #[inline]
    pub fn unpark_lock(&self) -> UnparkHandle {
        // We don't need to lock anything, just clear the state
        self.parked.store(UNPARKED, Ordering::Release);
        UnparkHandle(self.ptr())
    }

    #[inline]
    fn ptr(&self) -> *mut i32 {
        &self.parked as *const AtomicI32 as *mut i32
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle(*mut i32);

impl UnparkHandle {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    #[inline]
    pub fn unpark(self) {
        let num_notified = unsafe { wasm32::atomic_notify(self.0 as *mut i32, 1) };
        debug_assert!(num_notified == 0 || num_notified == 1);
    }
}

#[inline]
pub fn thread_yield() {
    thread::yield_now();
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![feature(phase)]
#![crate_name = "cube"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;

use cgmath::FixedArray;
use cgmath::{Matrix, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::{Device, DeviceHelper, ToSlice};
use glfw::Context;

#[vertex_format]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8, ..3],

    #[as_float]
    #[name = "a_TexCoord"]
    tex_coord: [u8, ..2],
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader. Its argument is the name of the type that will
// be generated to represent your the program. Search for `CubeBatch` below, to
// see how it's used.
#[shader_param(CubeBatch)]
struct Params {
    #[name = "u_Transform"]
    transform: [[f32, ..4], ..4],

    #[name = "t_Color"]
    color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource<'static> = shaders! {
GLSL_120: b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;

    uniform mat4 u_Transform;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 a_Pos;
    in vec2 a_TexCoord;
    out vec2 v_TexCoord;

    uniform mat4 u_Transform;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource<'static> = shaders! {
GLSL_120: b"
    #version 120

    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;

    void main() {
        vec4 tex = texture2D(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec2 v_TexCoord;
    out vec4 o_Color;

    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
    glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));

    let (window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| window.get_proc_address(s));

    let vertex_data = [
        // top (0, 0, 1)
        Vertex { pos: [-1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        // bottom (0, 0, -1)
        Vertex { pos: [-1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // right (1, 0, 0)
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 1] },
        // left (-1, 0, 0)
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // front (0, 1, 0)
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        // back (0, -1, 0)
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  5,  6,  6,  7,  4, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 13, 14, 14, 15, 12, // left
        16, 17, 18, 18, 19, 16, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = device
        .create_buffer_static::<u8>(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let texture_info = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let image_info = texture_info.to_image_info();
    let texture = device.create_texture(texture_info).unwrap();
    device.update_texture(&texture, &image_info,
                          &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
        .unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(gfx::tex::FilterMethod::Bilinear,
                                   gfx::tex::WrapMode::Clamp)
    );

    let program = device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                        .unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let mut graphics = gfx::Graphics::new(device);
    let batch: CubeBatch = graphics.make_batch(&program, &mesh, slice, &state).unwrap();

    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    let data = Params {
        transform: proj.mul_m(&view.mat).into_fixed(),
        color: (texture, Some(sampler)),
    };

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        graphics.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);
        graphics.draw(&batch, &data, &frame);
        graphics.end_frame();

        window.swap_buffers();
    }
}
<commit_msg>Demonstrate how to use lib without gfx::Graphics<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![feature(phase)]
#![crate_name = "cube"]

extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate glfw;

use cgmath::FixedArray;
use cgmath::{Matrix, Point3, Vector3};
use cgmath::{Transform, AffineMatrix3};
use gfx::{Device, DeviceHelper, ToSlice};
use gfx::batch;
use glfw::Context;

#[vertex_format]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8, ..3],

    #[as_float]
    #[name = "a_TexCoord"]
    tex_coord: [u8, ..2],
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader. Its argument is the name of the type that will
// be generated to represent your the program. Search for `CubeBatch` below, to
// see how it's used.
#[shader_param(CubeBatch)]
struct Params {
    #[name = "u_Transform"]
    transform: [[f32, ..4], ..4],

    #[name = "t_Color"]
    color: gfx::shade::TextureParam,
}

static VERTEX_SRC: gfx::ShaderSource<'static> = shaders! {
GLSL_120: b"
    #version 120

    attribute vec3 a_Pos;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;

    uniform mat4 u_Transform;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec3 a_Pos;
    in vec2 a_TexCoord;
    out vec2 v_TexCoord;

    uniform mat4 u_Transform;

    void main() {
        v_TexCoord = a_TexCoord;
        gl_Position = u_Transform * vec4(a_Pos, 1.0);
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource<'static> = shaders! {
GLSL_120: b"
    #version 120

    varying vec2 v_TexCoord;
    uniform sampler2D t_Color;

    void main() {
        vec4 tex = texture2D(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        gl_FragColor = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
GLSL_150: b"
    #version 150 core

    in vec2 v_TexCoord;
    out vec4 o_Color;

    uniform sampler2D t_Color;
    void main() {
        vec4 tex = texture(t_Color, v_TexCoord);
        float blend = dot(v_TexCoord-vec2(0.5,0.5), v_TexCoord-vec2(0.5,0.5));
        o_Color = mix(tex, vec4(0.0,0.0,0.0,0.0), blend*1.0);
    }
"
};

//----------------------------------------

fn main() {
    let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 2));
    glfw.window_hint(glfw::WindowHint::OpenglForwardCompat(true));
    glfw.window_hint(glfw::WindowHint::OpenglProfile(glfw::OpenGlProfileHint::Core));

    let (window, events) = glfw
        .create_window(640, 480, "Cube example", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    window.make_current();
    glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
    window.set_key_polling(true);

    let (w, h) = window.get_framebuffer_size();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx::GlDevice::new(|s| window.get_proc_address(s));
    let mut renderer = device.create_renderer();
    let mut context = batch::Context::new();

    let vertex_data = [
        // top (0, 0, 1)
        Vertex { pos: [-1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        // bottom (0, 0, -1)
        Vertex { pos: [-1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // right (1, 0, 0)
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 1] },
        // left (-1, 0, 0)
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // front (0, 1, 0)
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        // back (0, -1, 0)
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  5,  6,  6,  7,  4, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 13, 14, 14, 15, 12, // left
        16, 17, 18, 18, 19, 16, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = device
        .create_buffer_static::<u8>(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let texture_info = gfx::tex::TextureInfo {
        width: 1,
        height: 1,
        depth: 1,
        levels: 1,
        kind: gfx::tex::TextureKind::Texture2D,
        format: gfx::tex::RGBA8,
    };
    let image_info = texture_info.to_image_info();
    let texture = device.create_texture(texture_info).unwrap();
    device.update_texture(&texture, &image_info,
                          &[0x20u8, 0xA0u8, 0xC0u8, 0x00u8])
        .unwrap();

    let sampler = device.create_sampler(
        gfx::tex::SamplerInfo::new(gfx::tex::FilterMethod::Bilinear,
                                   gfx::tex::WrapMode::Clamp)
    );

    let program = device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                        .unwrap();
    let state = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);

    let batch: CubeBatch = context.make_batch(&program, &mesh, slice, &state).unwrap();

    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(45.0f32), aspect, 1.0, 10.0);

    let data = Params {
        transform: proj.mul_m(&view.mat).into_fixed(),
        color: (texture, Some(sampler)),
    };

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            match event {
                glfw::WindowEvent::Key(glfw::Key::Escape, _, glfw::Action::Press, _) =>
                    window.set_should_close(true),
                _ => {},
            }
        }

        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);
        renderer.draw((&batch, &data, &context), &frame);
        device.submit(renderer.as_buffer());
        renderer.reset();

        window.swap_buffers();
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::Write;

/// Defines whether a term in a query must be present,
/// should be present or must be not present.
#[derive(Debug, Clone, Hash, Copy, Eq, PartialEq)]
pub enum Occur {
    /// For a given document to be considered for scoring,
    /// at least one of the document with the Should or the Must
    /// Occur constraint must be within the document.
    Should,
    /// Document without the term are excluded from the search.
    Must,
    /// Document that contain the term are excluded from the
    /// search.
    MustNot,
}

impl Occur {
    /// Returns the one-char prefix symbol for this `Occur`.
    /// - `Should` => '?',
    /// - `Must` => '+'
    /// - `Not` => '-'
    fn to_char(self) -> char {
        match self {
            Occur::Should => '?',
            Occur::Must => '+',
            Occur::MustNot => '-',
        }
    }

    /// Compose two occur values.
    pub fn compose(left: Occur, right: Occur) -> Occur {
        match (left, right) {
            (Occur::Should, _) => { right }
            (Occur::Must, Occur::MustNot) => { Occur::MustNot }
            (Occur::Must, _) => { Occur::Must }
            (Occur::MustNot, Occur::MustNot) => { Occur::Must }
            (Occur::MustNot, _) => { Occur::MustNot }
        }
    }
}

impl fmt::Display for Occur {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_char(self.to_char())
    }
}

#[cfg(test)]
mod test {
    use crate::Occur;

    #[test]
    fn test_Occur_compose() {
        assert_eq!(Occur::compose(Occur::Should, Occur::Should), Occur::Should);
        assert_eq!(Occur::compose(Occur::Should, Occur::Must), Occur::Must);
        assert_eq!(Occur::compose(Occur::Should, Occur::MustNot), Occur::MustNot);
        assert_eq!(Occur::compose(Occur::Must, Occur::Should), Occur::Must);
        assert_eq!(Occur::compose(Occur::Must, Occur::Must), Occur::Must);
        assert_eq!(Occur::compose(Occur::Must, Occur::MustNot), Occur::MustNot);
        assert_eq!(Occur::compose(Occur::MustNot, Occur::Should), Occur::MustNot);
        assert_eq!(Occur::compose(Occur::MustNot, Occur::Must), Occur::MustNot);
        assert_eq!(Occur::compose(Occur::MustNot, Occur::MustNot), Occur::Must);
    }
}
<commit_msg>cargo fmt<commit_after>use std::fmt;
use std::fmt::Write;

/// Defines whether a term in a query must be present,
/// should be present or must be not present.
#[derive(Debug, Clone, Hash, Copy, Eq, PartialEq)]
pub enum Occur {
    /// For a given document to be considered for scoring,
    /// at least one of the document with the Should or the Must
    /// Occur constraint must be within the document.
    Should,
    /// Document without the term are excluded from the search.
    Must,
    /// Document that contain the term are excluded from the
    /// search.
    MustNot,
}

impl Occur {
    /// Returns the one-char prefix symbol for this `Occur`.
    /// - `Should` => '?',
    /// - `Must` => '+'
    /// - `Not` => '-'
    fn to_char(self) -> char {
        match self {
            Occur::Should => '?',
            Occur::Must => '+',
            Occur::MustNot => '-',
        }
    }

    /// Compose two occur values.
    pub fn compose(left: Occur, right: Occur) -> Occur {
        match (left, right) {
            (Occur::Should, _) => right,
            (Occur::Must, Occur::MustNot) => Occur::MustNot,
            (Occur::Must, _) => Occur::Must,
            (Occur::MustNot, Occur::MustNot) => Occur::Must,
            (Occur::MustNot, _) => Occur::MustNot,
        }
    }
}

impl fmt::Display for Occur {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_char(self.to_char())
    }
}

#[cfg(test)]
mod test {
    use crate::Occur;

    #[test]
    fn test_Occur_compose() {
        assert_eq!(Occur::compose(Occur::Should, Occur::Should), Occur::Should);
        assert_eq!(Occur::compose(Occur::Should, Occur::Must), Occur::Must);
        assert_eq!(
            Occur::compose(Occur::Should, Occur::MustNot),
            Occur::MustNot
        );
        assert_eq!(Occur::compose(Occur::Must, Occur::Should), Occur::Must);
        assert_eq!(Occur::compose(Occur::Must, Occur::Must), Occur::Must);
        assert_eq!(Occur::compose(Occur::Must, Occur::MustNot), Occur::MustNot);
        assert_eq!(
            Occur::compose(Occur::MustNot, Occur::Should),
            Occur::MustNot
        );
        assert_eq!(Occur::compose(Occur::MustNot, Occur::Must), Occur::MustNot);
        assert_eq!(Occur::compose(Occur::MustNot, Occur::MustNot), Occur::Must);
    }
}
<|endoftext|>


<commit_before>// Tuples can be used as function arguments and as return values
fn reverse(pair: (int, bool)) -> (bool, int) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // A tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using the `valN` methods
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // Tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // Tuples are printable
    println!("tuple of tuples: {}", tuple_of_tuples);

    let pair = (1, true);
    println!("pair is {}", pair);

    println!("the reversed pair is {}", reverse(pair));

    // To create one element tuples, the comma is required to tell them apart
    // from a literal surrounded by parentheses
    println!("one element tuple: {}", (5u,));
    println!("just an integer: {}", (5u));
}
<commit_msg>Update tuples.rs<commit_after>// Tuples can be used as function arguments and as return values
fn reverse(pair: (int, bool)) -> (bool, int) {
    // `let` can be used to bind the members of a tuple to variables
    let (integer, boolean) = pair;

    (boolean, integer)
}

fn main() {
    // A tuple with a bunch of different types
    let long_tuple = (1u8, 2u16, 3u32, 4u64,
                      -1i8, -2i16, -3i32, -4i64,
                      0.1f32, 0.2f64,
                      'a', true);

    // Values can be extracted from the tuple using the `.N` syntax
    println!("long tuple first value: {}", long_tuple.0);
    println!("long tuple second value: {}", long_tuple.1);

    // Tuples can be tuple members
    let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);

    // Tuples are printable
    println!("tuple of tuples: {}", tuple_of_tuples);

    let pair = (1, true);
    println!("pair is {}", pair);

    println!("the reversed pair is {}", reverse(pair));

    // To create one element tuples, the comma is required to tell them apart
    // from a literal surrounded by parentheses
    println!("one element tuple: {}", (5u,));
    println!("just an integer: {}", (5u));
}
<|endoftext|>


<commit_before>use lazy_static::lazy_static;
use maplit::hashmap;
use serde_json::json;
use std::collections::HashMap;

use crate::game_object::GameObject;
use crate::logs::{log_session_event, LogSender};
use crate::objects::{Player, Realm};
use crate::sessions::SessionOutput as Output;
use crate::text_utils::is_letter;

use super::sign_up::{
    enter_sign_up_step, exit_sign_up_step, process_sign_up_input, prompt_sign_up_step, SignUpData,
    SignUpState,
};

#[derive(Clone, Debug, PartialEq)]
pub struct SignInState {
    step: SignInStep,
    data: SignInData,
}

impl SignInState {
    pub fn get_sign_in_user_name(&self) -> Option<&str> {
        if self.step == SignInStep::SignedIn {
            if let Some(player) = &self.data.player {
                Some(player.get_name())
            } else if let Some(sign_up_state) = &self.data.sign_up_state {
                Some(&sign_up_state.data.user_name)
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_sign_up_data(&self) -> Option<&SignUpData> {
        if self.step == SignInStep::SignedIn {
            self.data.sign_up_state.as_ref().map(|state| &state.data)
        } else {
            None
        }
    }

    pub fn is_session_closed(&self) -> bool {
        self.step == SignInStep::SessionClosed
    }

    pub fn new() -> Self {
        new_state(
            SignInStep::AskingUserName,
            SignInData {
                player: None,
                sign_up_state: None,
            },
        )
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum SignInStep {
    AskingPassword,
    AskingSignUpData,
    AskingUserName,
    SessionClosed,
    SignedIn,
}

#[derive(Clone, Debug, PartialEq)]
struct SignInData {
    player: Option<Player>,
    sign_up_state: Option<SignUpState>,
}

struct StepImpl {
    enter: fn(&SignInData, &Realm) -> Output,
    exit: fn(&SignInData) -> Output,
    prompt: fn(&SignInData) -> Output,
    process_input: fn(&SignInState, &Realm, &LogSender, &String, String) -> (SignInState, Output),
}

pub fn process_input(
    state: &SignInState,
    realm: &Realm,
    log_tx: &LogSender,
    source: &String,
    input: String,
) -> (SignInState, Output) {
    lazy_static! {
        static ref SIGN_IN_STEPS: HashMap<SignInStep, StepImpl> = get_sign_in_steps();
    }

    match SIGN_IN_STEPS.get(&state.step) {
        Some(step) => {
            let (new_state, output) = (step.process_input)(state, realm, log_tx, source, input);
            if let Some(new_step) = SIGN_IN_STEPS.get(&new_state.step) {
                let prompt_output = (new_step.prompt)(&new_state.data);
                let outputs = if new_state == *state {
                    vec![output, prompt_output]
                } else {
                    let exit_output = (step.exit)(&new_state.data);
                    let enter_output = (new_step.enter)(&new_state.data, realm);
                    vec![output, exit_output, enter_output, prompt_output]
                };

                (new_state, Output::combine(outputs).process_highlights())
            } else {
                (new_state, output)
            }
        }
        None => (state.clone(), Output::None),
    }
}

fn get_sign_in_steps() -> HashMap<SignInStep, StepImpl> {
    hashmap! {
        SignInStep::AskingUserName => StepImpl {
            enter: |_, _| Output::None,
            exit: |_| Output::None,
            prompt: |_| Output::Str("What is your name? "),
            process_input: process_asking_user_name_input,
        },

        SignInStep::AskingPassword => StepImpl {
            enter: |_, _| Output::JSON(json!({ "inputType": "password" })),
            exit: |_| Output::JSON(json!({ "inputType": "text" })),
            prompt: |_| Output::Str("Please enter your password: "),
            process_input: process_asking_password_input,
        },

        SignInStep::AskingSignUpData => StepImpl {
            enter: |data, realm| enter_sign_up_step(&data.sign_up_state.as_ref().unwrap(), realm),
            exit: |data| exit_sign_up_step(&data.sign_up_state.as_ref().unwrap()),
            prompt: |data| prompt_sign_up_step(&data.sign_up_state.as_ref().unwrap()),
            process_input: |state, realm, _, _, input| {
                let (sign_up_state, output) = process_sign_up_input(
                    &state.data.sign_up_state.as_ref().unwrap(),
                    realm,
                    input
                );
                (
                    new_state(
                        if sign_up_state.is_session_closed() {
                            SignInStep::SessionClosed
                        } else if sign_up_state.is_signed_up() {
                            SignInStep::SignedIn
                        } else {
                            SignInStep::AskingSignUpData
                        },
                        SignInData { sign_up_state: Some(sign_up_state), ..state.data.clone() }
                    ),
                    output
                )
            }
        }
    }
}

fn new_state(step: SignInStep, data: SignInData) -> SignInState {
    SignInState { step, data }
}

fn process_asking_user_name_input(
    state: &SignInState,
    realm: &Realm,
    _: &LogSender,
    _: &String,
    input: String,
) -> (SignInState, Output) {
    lazy_static! {
        static ref RESERVED_NAMES: Vec<String> = vec![
            "Admin".to_owned(),
            "Administrator".to_owned(),
            "Root".to_owned()
        ];
    }
    let user_name = validate_user_name(input.to_lowercase());
    if user_name.len() < 3 {
        (
            state.clone(),
            if user_name.len() == 0 {
                Output::None
            } else {
                Output::Str("I'm sorry, but your name should consist of at least 3 letters.\n")
            },
        )
    } else if let Some(player) = realm.get_player_by_name(&user_name) {
        (
            new_state(
                SignInStep::AskingPassword,
                SignInData {
                    player: Some(player),
                    ..state.data.clone()
                },
            ),
            Output::None,
        )
    } else if RESERVED_NAMES.contains(&user_name) {
        (
            state.clone(),
            Output::Str("Yeah right, like I believe that...\n"),
        )
    } else {
        (
            new_state(
                SignInStep::AskingSignUpData,
                SignInData {
                    sign_up_state: Some(SignUpState::new(user_name)),
                    ..state.data.clone()
                },
            ),
            Output::None,
        )
    }
}

fn process_asking_password_input(
    state: &SignInState,
    _: &Realm,
    log_tx: &LogSender,
    source: &String,
    input: String,
) -> (SignInState, Output) {
    if let Some(player) = &state.data.player {
        let name = player.get_name();
        if player.matches_password(&input) {
            log_session_event(
                log_tx,
                source.clone(),
                format!("Authentication success for player \"{}\"", name),
            );

            if player.get_session_id().is_some() {
                (
                    new_state(SignInStep::SessionClosed, state.data.clone()),
                    Output::Str(
                        "Cannot sign you in because you're already signed in from another \
                        location.\n",
                    ),
                )
            } else {
                (
                    new_state(SignInStep::SignedIn, state.data.clone()),
                    Output::String(format!(
                        "Welcome back, {}. Type *help* if you're feeling lost.\n",
                        name
                    )),
                )
            }
        } else {
            log_session_event(
                log_tx,
                source.clone(),
                format!("Authentication failed for player \"{}\"", name),
            );

            (state.clone(), Output::Str("Password incorrect.\n"))
        }
    } else {
        (state.clone(), Output::None)
    }
}

fn validate_user_name(input: String) -> String {
    let mut user_name = String::new();
    let mut num_special_chars = 0;
    for character in input.chars() {
        if is_letter(character) {
            user_name.push(if user_name.len() == 0 {
                character.to_ascii_uppercase()
            } else {
                character
            });
        } else if user_name.len() > 0
            && num_special_chars == 0
            && (character == '\'' || character == '-')
        {
            user_name.push(character);
            num_special_chars += 1;
        }
        if user_name.len() >= 12 {
            break;
        }
    }
    if user_name.len() > 1 && !is_letter(user_name.chars().rev().next().unwrap_or_default()) {
        user_name = user_name.chars().take(user_name.len() - 1).collect();
    }
    user_name
}
<commit_msg>Add missing highlighting<commit_after>use lazy_static::lazy_static;
use maplit::hashmap;
use serde_json::json;
use std::collections::HashMap;

use crate::game_object::GameObject;
use crate::logs::{log_session_event, LogSender};
use crate::objects::{Player, Realm};
use crate::sessions::SessionOutput as Output;
use crate::text_utils::is_letter;

use super::sign_up::{
    enter_sign_up_step, exit_sign_up_step, process_sign_up_input, prompt_sign_up_step, SignUpData,
    SignUpState,
};

#[derive(Clone, Debug, PartialEq)]
pub struct SignInState {
    step: SignInStep,
    data: SignInData,
}

impl SignInState {
    pub fn get_sign_in_user_name(&self) -> Option<&str> {
        if self.step == SignInStep::SignedIn {
            if let Some(player) = &self.data.player {
                Some(player.get_name())
            } else if let Some(sign_up_state) = &self.data.sign_up_state {
                Some(&sign_up_state.data.user_name)
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_sign_up_data(&self) -> Option<&SignUpData> {
        if self.step == SignInStep::SignedIn {
            self.data.sign_up_state.as_ref().map(|state| &state.data)
        } else {
            None
        }
    }

    pub fn is_session_closed(&self) -> bool {
        self.step == SignInStep::SessionClosed
    }

    pub fn new() -> Self {
        new_state(
            SignInStep::AskingUserName,
            SignInData {
                player: None,
                sign_up_state: None,
            },
        )
    }
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
enum SignInStep {
    AskingPassword,
    AskingSignUpData,
    AskingUserName,
    SessionClosed,
    SignedIn,
}

#[derive(Clone, Debug, PartialEq)]
struct SignInData {
    player: Option<Player>,
    sign_up_state: Option<SignUpState>,
}

struct StepImpl {
    enter: fn(&SignInData, &Realm) -> Output,
    exit: fn(&SignInData) -> Output,
    prompt: fn(&SignInData) -> Output,
    process_input: fn(&SignInState, &Realm, &LogSender, &String, String) -> (SignInState, Output),
}

pub fn process_input(
    state: &SignInState,
    realm: &Realm,
    log_tx: &LogSender,
    source: &String,
    input: String,
) -> (SignInState, Output) {
    lazy_static! {
        static ref SIGN_IN_STEPS: HashMap<SignInStep, StepImpl> = get_sign_in_steps();
    }

    match SIGN_IN_STEPS.get(&state.step) {
        Some(step) => {
            let (new_state, output) = (step.process_input)(state, realm, log_tx, source, input);
            if let Some(new_step) = SIGN_IN_STEPS.get(&new_state.step) {
                let prompt_output = (new_step.prompt)(&new_state.data);
                let outputs = if new_state == *state {
                    vec![output, prompt_output]
                } else {
                    let exit_output = (step.exit)(&new_state.data);
                    let enter_output = (new_step.enter)(&new_state.data, realm);
                    vec![output, exit_output, enter_output, prompt_output]
                };

                (new_state, Output::combine(outputs).process_highlights())
            } else {
                (new_state, output.process_highlights())
            }
        }
        None => (state.clone(), Output::None),
    }
}

fn get_sign_in_steps() -> HashMap<SignInStep, StepImpl> {
    hashmap! {
        SignInStep::AskingUserName => StepImpl {
            enter: |_, _| Output::None,
            exit: |_| Output::None,
            prompt: |_| Output::Str("What is your name? "),
            process_input: process_asking_user_name_input,
        },

        SignInStep::AskingPassword => StepImpl {
            enter: |_, _| Output::JSON(json!({ "inputType": "password" })),
            exit: |_| Output::JSON(json!({ "inputType": "text" })),
            prompt: |_| Output::Str("Please enter your password: "),
            process_input: process_asking_password_input,
        },

        SignInStep::AskingSignUpData => StepImpl {
            enter: |data, realm| enter_sign_up_step(&data.sign_up_state.as_ref().unwrap(), realm),
            exit: |data| exit_sign_up_step(&data.sign_up_state.as_ref().unwrap()),
            prompt: |data| prompt_sign_up_step(&data.sign_up_state.as_ref().unwrap()),
            process_input: |state, realm, _, _, input| {
                let (sign_up_state, output) = process_sign_up_input(
                    &state.data.sign_up_state.as_ref().unwrap(),
                    realm,
                    input
                );
                (
                    new_state(
                        if sign_up_state.is_session_closed() {
                            SignInStep::SessionClosed
                        } else if sign_up_state.is_signed_up() {
                            SignInStep::SignedIn
                        } else {
                            SignInStep::AskingSignUpData
                        },
                        SignInData { sign_up_state: Some(sign_up_state), ..state.data.clone() }
                    ),
                    output
                )
            }
        }
    }
}

fn new_state(step: SignInStep, data: SignInData) -> SignInState {
    SignInState { step, data }
}

fn process_asking_user_name_input(
    state: &SignInState,
    realm: &Realm,
    _: &LogSender,
    _: &String,
    input: String,
) -> (SignInState, Output) {
    lazy_static! {
        static ref RESERVED_NAMES: Vec<String> = vec![
            "Admin".to_owned(),
            "Administrator".to_owned(),
            "Root".to_owned()
        ];
    }
    let user_name = validate_user_name(input.to_lowercase());
    if user_name.len() < 3 {
        (
            state.clone(),
            if user_name.len() == 0 {
                Output::None
            } else {
                Output::Str("I'm sorry, but your name should consist of at least 3 letters.\n")
            },
        )
    } else if let Some(player) = realm.get_player_by_name(&user_name) {
        (
            new_state(
                SignInStep::AskingPassword,
                SignInData {
                    player: Some(player),
                    ..state.data.clone()
                },
            ),
            Output::None,
        )
    } else if RESERVED_NAMES.contains(&user_name) {
        (
            state.clone(),
            Output::Str("Yeah right, like I believe that...\n"),
        )
    } else {
        (
            new_state(
                SignInStep::AskingSignUpData,
                SignInData {
                    sign_up_state: Some(SignUpState::new(user_name)),
                    ..state.data.clone()
                },
            ),
            Output::None,
        )
    }
}

fn process_asking_password_input(
    state: &SignInState,
    _: &Realm,
    log_tx: &LogSender,
    source: &String,
    input: String,
) -> (SignInState, Output) {
    if let Some(player) = &state.data.player {
        let name = player.get_name();
        if player.matches_password(&input) {
            log_session_event(
                log_tx,
                source.clone(),
                format!("Authentication success for player \"{}\"", name),
            );

            if player.get_session_id().is_some() {
                (
                    new_state(SignInStep::SessionClosed, state.data.clone()),
                    Output::Str(
                        "Cannot sign you in because you're already signed in from another \
                        location.\n",
                    ),
                )
            } else {
                (
                    new_state(SignInStep::SignedIn, state.data.clone()),
                    Output::String(format!(
                        "Welcome back, {}. Type *help* if you're feeling lost.\n",
                        name
                    )),
                )
            }
        } else {
            log_session_event(
                log_tx,
                source.clone(),
                format!("Authentication failed for player \"{}\"", name),
            );

            (state.clone(), Output::Str("Password incorrect.\n"))
        }
    } else {
        (state.clone(), Output::None)
    }
}

fn validate_user_name(input: String) -> String {
    let mut user_name = String::new();
    let mut num_special_chars = 0;
    for character in input.chars() {
        if is_letter(character) {
            user_name.push(if user_name.len() == 0 {
                character.to_ascii_uppercase()
            } else {
                character
            });
        } else if user_name.len() > 0
            && num_special_chars == 0
            && (character == '\'' || character == '-')
        {
            user_name.push(character);
            num_special_chars += 1;
        }
        if user_name.len() >= 12 {
            break;
        }
    }
    if user_name.len() > 1 && !is_letter(user_name.chars().rev().next().unwrap_or_default()) {
        user_name = user_name.chars().take(user_name.len() - 1).collect();
    }
    user_name
}
<|endoftext|>


<commit_before>// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustlings run --test exercises/tests/tests1.rs

// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)

// I AM NOT DONE

#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert() {
        assert!();
    }
}
<commit_msg>fix(tests1): Change test command<commit_after>// tests1.rs
// Tests are important to ensure that your code does what you think it should do.
// Tests can be run on this file with the following command:
// rustlings run exercises/tests/tests1.rs

// This test has a problem with it -- make the test compile! Make the test
// pass! Make the test fail! Execute `rustlings hint tests1` for hints :)

// I AM NOT DONE

#[cfg(test)]
mod tests {
    #[test]
    fn you_can_assert() {
        assert!();
    }
}
<|endoftext|>