<commit_before>//! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-login)

use std::borrow::Cow;

use ruma_api::ruma_api;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::MxcUri;
#[cfg(feature = "unstable-pre-spec")]
use ruma_serde::StringEnum;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value as JsonValue;

type JsonObject = serde_json::Map<String, JsonValue>;

ruma_api! {
    metadata: {
        description: "Gets the homeserver's supported login types to authenticate users. Clients should pick one of these and supply it as the type when logging in.",
        method: GET,
        name: "get_login_types",
        path: "/_matrix/client/r0/login",
        rate_limited: true,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    response: {
        /// The homeserver's supported login types.
        pub flows: Vec<LoginType>,
    }

    error: crate::Error
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self
    }
}

impl Response {
    /// Creates a new `Response` with the given login types.
    pub fn new(flows: Vec<LoginType>) -> Self {
        Self { flows }
    }
}

/// An authentication mechanism.
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum LoginType {
    /// A password is supplied to authenticate.
    Password(PasswordLoginType),

    /// Token-based login.
    Token(TokenLoginType),

    /// SSO-based login.
    Sso(SsoLoginType),

    /// Custom login type.
    #[doc(hidden)]
    _Custom(CustomLoginType),
}

impl LoginType {
    /// Creates a `LoginType` with the given `login_type` string and data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this constructor is meant
    /// be used for unsupported login types only and does not allow setting arbitrary data for
    /// supported ones.
    pub fn new(login_type: &str, data: JsonObject) -> serde_json::Result<Self> {
        fn from_json_object<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
            serde_json::from_value(JsonValue::Object(obj))
        }

        Ok(match login_type {
            "m.login.password" => Self::Password(from_json_object(data)?),
            "m.login.token" => Self::Token(from_json_object(data)?),
            "m.login.sso" => Self::Sso(from_json_object(data)?),
            _ => Self::_Custom(CustomLoginType { type_: login_type.to_owned(), data }),
        })
    }

    /// Returns a reference to the `login_type` string.
    pub fn login_type(&self) -> &str {
        match self {
            Self::Password(_) => "m.login.password",
            Self::Token(_) => "m.login.token",
            Self::Sso(_) => "m.login.sso",
            Self::_Custom(c) => &c.type_,
        }
    }

    /// Returns the associated data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this method is meant to
    /// be used for unsupported login types only.
    pub fn data(&self) -> Cow<'_, JsonObject> {
        fn serialize<T: Serialize>(obj: &T) -> JsonObject {
            match serde_json::to_value(obj).expect("login type serialization to succeed") {
                JsonValue::Object(obj) => obj,
                _ => panic!("all login types must serialize to objects"),
            }
        }

        match self {
            Self::Password(d) => Cow::Owned(serialize(d)),
            Self::Token(d) => Cow::Owned(serialize(d)),
            Self::Sso(d) => Cow::Owned(serialize(d)),
            Self::_Custom(c) => Cow::Borrowed(&c.data),
        }
    }
}

/// The payload for password login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.password")]
pub struct PasswordLoginType {}

impl PasswordLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for token-based login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.token")]
pub struct TokenLoginType {}

impl TokenLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for SSO login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.sso")]
pub struct SsoLoginType {
    /// The identity provider choices.
    ///
    /// This uses the unstable prefix in
    /// [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858).
    #[cfg(feature = "unstable-pre-spec")]
    #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
    #[serde(
        default,
        rename = "org.matrix.msc2858.identity_providers",
        skip_serializing_if = "Vec::is_empty"
    )]
    pub identity_providers: Vec<IdentityProvider>,
}

impl SsoLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self::default()
    }
}

/// An SSO login identity provider.
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IdentityProvider {
    /// The ID of the provider.
    id: String,

    /// The display name of the provider.
    name: String,

    /// The icon for the provider.
    icon: Option<MxcUri>,

    /// The brand identifier for the provider.
    brand: Option<IdentityProviderBrand>,
}

#[cfg(feature = "unstable-pre-spec")]
impl IdentityProvider {
    /// Creates an `IdentityProvider` with the given `id` and `name`.
    pub fn new(id: String, name: String) -> Self {
        Self { id, name, icon: None, brand: None }
    }
}

/// An SSO login identity provider brand identifier.
///
/// This uses the unstable prefix in
/// [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858).
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum IdentityProviderBrand {
    /// The [Apple] brand.
    ///
    /// [Apple]: https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/buttons/
    #[ruma_enum(rename = "org.matrix.apple")]
    Apple,

    /// The [Facebook](https://developers.facebook.com/docs/facebook-login/web/login-button/) brand.
    #[ruma_enum(rename = "org.matrix.facebook")]
    Facebook,

    /// The [GitHub](https://github.com/logos) brand.
    #[ruma_enum(rename = "org.matrix.github")]
    GitHub,

    /// The [GitLab](https://about.gitlab.com/press/press-kit/) brand.
    #[ruma_enum(rename = "org.matrix.gitlab")]
    GitLab,

    /// The [Google](https://developers.google.com/identity/branding-guidelines) brand.
    #[ruma_enum(rename = "org.matrix.google")]
    Google,

    /// The [Twitter] brand.
    ///
    /// [Twitter]: https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter#tab1
    #[ruma_enum(rename = "org.matrix.twitter")]
    Twitter,

    /// A custom brand.
    #[doc(hidden)]
    _Custom(String),
}

/// A custom login payload.
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CustomLoginType {
    /// A custom type
    ///
    /// This field is named `type_` instead of `type` because the latter is a reserved
    /// keyword in Rust.
    #[serde(rename = "override")]
    pub type_: String,

    /// Remaining type content
    #[serde(flatten)]
    pub data: JsonObject,
}

mod login_type_serde;

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde::{Deserialize, Serialize};
    #[cfg(feature = "unstable-pre-spec")]
    use serde_json::to_value as to_json_value;
    use serde_json::{from_value as from_json_value, json};

    #[cfg(feature = "unstable-pre-spec")]
    use super::{IdentityProvider, IdentityProviderBrand, SsoLoginType, TokenLoginType};
    use super::{LoginType, PasswordLoginType};

    #[derive(Debug, Deserialize, Serialize)]
    struct Foo {
        pub flows: Vec<LoginType>,
    }

    #[test]
    fn deserialize_password_login_type() {
        assert_matches!(
            from_json_value::<Foo>(json!({
                "flows": [
                    { "type": "m.login.password" }
                ],
            })),
            Ok(Foo { flows })
            if flows.len() == 1
                && matches!(flows[0], LoginType::Password(PasswordLoginType {}))
        );
    }

    #[test]
    #[cfg(feature = "unstable-pre-spec")]
    fn deserialize_sso_login_type() {
        let mut foo = from_json_value::<Foo>(json!({
            "flows": [
                {
                    "type": "m.login.sso",
                    "org.matrix.msc2858.identity_providers": [
                        {
                            "id": "oidc-gitlab",
                            "name": "GitLab",
                            "icon": "mxc://localhost/gitlab-icon",
                            "brand": "org.matrix.gitlab"
                        },
                        {
                            "id": "custom",
                            "name": "Custom",
                        }
                    ]
                }
            ],
        }))
        .unwrap();

        let mut flow = foo.flows.pop();
        assert_matches!(foo.flows.as_slice(), []);

        let mut identity_providers = match flow {
            Some(LoginType::Sso(SsoLoginType { identity_providers })) => identity_providers,
            _ => panic!("unexpected enum variant: {:?}", flow),
        };

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: None,
                brand: None,
            }) if id == "custom"
                && name == "Custom"
        );

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: Some(icon),
                brand: Some(IdentityProviderBrand::GitLab),
            }) if id == "oidc-gitlab"
                && name == "GitLab"
                && icon.to_string() == "mxc://localhost/gitlab-icon"
        );
    }

    #[test]
    #[cfg(feature = "unstable-pre-spec")]
    fn serialize_sso_login_type() {
        let foo = to_json_value(Foo {
            flows: vec![
                LoginType::Token(TokenLoginType {}),
                LoginType::Sso(SsoLoginType {
                    identity_providers: vec![IdentityProvider {
                        id: "oidc-github".into(),
                        name: "GitHub".into(),
                        icon: Some("mxc://localhost/github-icon".into()),
                        brand: Some(IdentityProviderBrand::GitHub),
                    }],
                }),
            ],
        })
        .unwrap();

        assert_eq!(
            foo,
            json!({
                "flows": [
                    {
                        "type": "m.login.token"
                    },
                    {
                        "type": "m.login.sso",
                        "org.matrix.msc2858.identity_providers": [
                            {
                                "id": "oidc-github",
                                "name": "GitHub",
                                "icon": "mxc://localhost/github-icon",
                                "brand": "org.matrix.github"
                            },
                        ]
                    }
                ],
            })
        );
    }
}
<commit_msg>client-api: Fix warning in tests<commit_after>//! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-login)

use std::borrow::Cow;

use ruma_api::ruma_api;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::MxcUri;
#[cfg(feature = "unstable-pre-spec")]
use ruma_serde::StringEnum;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value as JsonValue;

type JsonObject = serde_json::Map<String, JsonValue>;

ruma_api! {
    metadata: {
        description: "Gets the homeserver's supported login types to authenticate users. Clients should pick one of these and supply it as the type when logging in.",
        method: GET,
        name: "get_login_types",
        path: "/_matrix/client/r0/login",
        rate_limited: true,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    response: {
        /// The homeserver's supported login types.
        pub flows: Vec<LoginType>,
    }

    error: crate::Error
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self
    }
}

impl Response {
    /// Creates a new `Response` with the given login types.
    pub fn new(flows: Vec<LoginType>) -> Self {
        Self { flows }
    }
}

/// An authentication mechanism.
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum LoginType {
    /// A password is supplied to authenticate.
    Password(PasswordLoginType),

    /// Token-based login.
    Token(TokenLoginType),

    /// SSO-based login.
    Sso(SsoLoginType),

    /// Custom login type.
    #[doc(hidden)]
    _Custom(CustomLoginType),
}

impl LoginType {
    /// Creates a `LoginType` with the given `login_type` string and data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this constructor is meant
    /// be used for unsupported login types only and does not allow setting arbitrary data for
    /// supported ones.
    pub fn new(login_type: &str, data: JsonObject) -> serde_json::Result<Self> {
        fn from_json_object<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
            serde_json::from_value(JsonValue::Object(obj))
        }

        Ok(match login_type {
            "m.login.password" => Self::Password(from_json_object(data)?),
            "m.login.token" => Self::Token(from_json_object(data)?),
            "m.login.sso" => Self::Sso(from_json_object(data)?),
            _ => Self::_Custom(CustomLoginType { type_: login_type.to_owned(), data }),
        })
    }

    /// Returns a reference to the `login_type` string.
    pub fn login_type(&self) -> &str {
        match self {
            Self::Password(_) => "m.login.password",
            Self::Token(_) => "m.login.token",
            Self::Sso(_) => "m.login.sso",
            Self::_Custom(c) => &c.type_,
        }
    }

    /// Returns the associated data.
    ///
    /// Prefer to use the public variants of `LoginType` where possible; this method is meant to
    /// be used for unsupported login types only.
    pub fn data(&self) -> Cow<'_, JsonObject> {
        fn serialize<T: Serialize>(obj: &T) -> JsonObject {
            match serde_json::to_value(obj).expect("login type serialization to succeed") {
                JsonValue::Object(obj) => obj,
                _ => panic!("all login types must serialize to objects"),
            }
        }

        match self {
            Self::Password(d) => Cow::Owned(serialize(d)),
            Self::Token(d) => Cow::Owned(serialize(d)),
            Self::Sso(d) => Cow::Owned(serialize(d)),
            Self::_Custom(c) => Cow::Borrowed(&c.data),
        }
    }
}

/// The payload for password login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.password")]
pub struct PasswordLoginType {}

impl PasswordLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for token-based login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.token")]
pub struct TokenLoginType {}

impl TokenLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self {}
    }
}

/// The payload for SSO login.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(tag = "type", rename = "m.login.sso")]
pub struct SsoLoginType {
    /// The identity provider choices.
    ///
    /// This uses the unstable prefix in
    /// [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858).
    #[cfg(feature = "unstable-pre-spec")]
    #[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
    #[serde(
        default,
        rename = "org.matrix.msc2858.identity_providers",
        skip_serializing_if = "Vec::is_empty"
    )]
    pub identity_providers: Vec<IdentityProvider>,
}

impl SsoLoginType {
    /// Creates a new `PasswordLoginType`.
    pub fn new() -> Self {
        Self::default()
    }
}

/// An SSO login identity provider.
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct IdentityProvider {
    /// The ID of the provider.
    id: String,

    /// The display name of the provider.
    name: String,

    /// The icon for the provider.
    icon: Option<MxcUri>,

    /// The brand identifier for the provider.
    brand: Option<IdentityProviderBrand>,
}

#[cfg(feature = "unstable-pre-spec")]
impl IdentityProvider {
    /// Creates an `IdentityProvider` with the given `id` and `name`.
    pub fn new(id: String, name: String) -> Self {
        Self { id, name, icon: None, brand: None }
    }
}

/// An SSO login identity provider brand identifier.
///
/// This uses the unstable prefix in
/// [MSC2858](https://github.com/matrix-org/matrix-doc/pull/2858).
#[cfg(feature = "unstable-pre-spec")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable-pre-spec")))]
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum IdentityProviderBrand {
    /// The [Apple] brand.
    ///
    /// [Apple]: https://developer.apple.com/design/human-interface-guidelines/sign-in-with-apple/overview/buttons/
    #[ruma_enum(rename = "org.matrix.apple")]
    Apple,

    /// The [Facebook](https://developers.facebook.com/docs/facebook-login/web/login-button/) brand.
    #[ruma_enum(rename = "org.matrix.facebook")]
    Facebook,

    /// The [GitHub](https://github.com/logos) brand.
    #[ruma_enum(rename = "org.matrix.github")]
    GitHub,

    /// The [GitLab](https://about.gitlab.com/press/press-kit/) brand.
    #[ruma_enum(rename = "org.matrix.gitlab")]
    GitLab,

    /// The [Google](https://developers.google.com/identity/branding-guidelines) brand.
    #[ruma_enum(rename = "org.matrix.google")]
    Google,

    /// The [Twitter] brand.
    ///
    /// [Twitter]: https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter#tab1
    #[ruma_enum(rename = "org.matrix.twitter")]
    Twitter,

    /// A custom brand.
    #[doc(hidden)]
    _Custom(String),
}

/// A custom login payload.
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct CustomLoginType {
    /// A custom type
    ///
    /// This field is named `type_` instead of `type` because the latter is a reserved
    /// keyword in Rust.
    #[serde(rename = "override")]
    pub type_: String,

    /// Remaining type content
    #[serde(flatten)]
    pub data: JsonObject,
}

mod login_type_serde;

#[cfg(test)]
mod tests {
    use matches::assert_matches;
    use serde::{Deserialize, Serialize};
    #[cfg(feature = "unstable-pre-spec")]
    use serde_json::to_value as to_json_value;
    use serde_json::{from_value as from_json_value, json};

    #[cfg(feature = "unstable-pre-spec")]
    use super::{IdentityProvider, IdentityProviderBrand, SsoLoginType, TokenLoginType};
    use super::{LoginType, PasswordLoginType};

    #[derive(Debug, Deserialize, Serialize)]
    struct Foo {
        pub flows: Vec<LoginType>,
    }

    #[test]
    fn deserialize_password_login_type() {
        assert_matches!(
            from_json_value::<Foo>(json!({
                "flows": [
                    { "type": "m.login.password" }
                ],
            })),
            Ok(Foo { flows })
            if flows.len() == 1
                && matches!(flows[0], LoginType::Password(PasswordLoginType {}))
        );
    }

    #[test]
    #[cfg(feature = "unstable-pre-spec")]
    fn deserialize_sso_login_type() {
        let mut foo = from_json_value::<Foo>(json!({
            "flows": [
                {
                    "type": "m.login.sso",
                    "org.matrix.msc2858.identity_providers": [
                        {
                            "id": "oidc-gitlab",
                            "name": "GitLab",
                            "icon": "mxc://localhost/gitlab-icon",
                            "brand": "org.matrix.gitlab"
                        },
                        {
                            "id": "custom",
                            "name": "Custom",
                        }
                    ]
                }
            ],
        }))
        .unwrap();

        let flow = foo.flows.pop();
        assert_matches!(foo.flows.as_slice(), []);

        let mut identity_providers = match flow {
            Some(LoginType::Sso(SsoLoginType { identity_providers })) => identity_providers,
            _ => panic!("unexpected enum variant: {:?}", flow),
        };

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: None,
                brand: None,
            }) if id == "custom"
                && name == "Custom"
        );

        let provider = identity_providers.pop();
        assert_matches!(
            provider,
            Some(IdentityProvider {
                id,
                name,
                icon: Some(icon),
                brand: Some(IdentityProviderBrand::GitLab),
            }) if id == "oidc-gitlab"
                && name == "GitLab"
                && icon.to_string() == "mxc://localhost/gitlab-icon"
        );
    }

    #[test]
    #[cfg(feature = "unstable-pre-spec")]
    fn serialize_sso_login_type() {
        let foo = to_json_value(Foo {
            flows: vec![
                LoginType::Token(TokenLoginType {}),
                LoginType::Sso(SsoLoginType {
                    identity_providers: vec![IdentityProvider {
                        id: "oidc-github".into(),
                        name: "GitHub".into(),
                        icon: Some("mxc://localhost/github-icon".into()),
                        brand: Some(IdentityProviderBrand::GitHub),
                    }],
                }),
            ],
        })
        .unwrap();

        assert_eq!(
            foo,
            json!({
                "flows": [
                    {
                        "type": "m.login.token"
                    },
                    {
                        "type": "m.login.sso",
                        "org.matrix.msc2858.identity_providers": [
                            {
                                "id": "oidc-github",
                                "name": "GitHub",
                                "icon": "mxc://localhost/github-icon",
                                "brand": "org.matrix.github"
                            },
                        ]
                    }
                ],
            })
        );
    }
}
<|endoftext|>


<commit_before>pub enum Key {
    Up,
    Right,
    Down,
    Left,
    RightTurn,
    LeftTurn,
    Start,
}
<commit_msg>Add Key::parse_char<commit_after>#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Key {
    Up,
    Right,
    Down,
    Left,
    RightTurn,
    LeftTurn,
    Start,
}

impl Key {
    pub fn parse_char(c: char) -> Result<Key, String> {
        match c {
            '^' => Ok(Key::Up),
            '>' => Ok(Key::Right),
            'v' => Ok(Key::Down),
            '<' => Ok(Key::Left),
            'A' => Ok(Key::RightTurn),
            'B' => Ok(Key::LeftTurn),
            'S' => Ok(Key::Start),
            _ => Err(format!("Unknown key character: {}", c)),
        }
    }
}

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

    #[test]
    fn test_parse_char() {
        assert_eq!(Key::Up, Key::parse_char('^').unwrap());
        assert_eq!(Key::Right, Key::parse_char('>').unwrap());
        assert_eq!(Key::Down, Key::parse_char('v').unwrap());
        assert_eq!(Key::Left, Key::parse_char('<').unwrap());
        assert_eq!(Key::RightTurn, Key::parse_char('A').unwrap());
        assert_eq!(Key::LeftTurn, Key::parse_char('B').unwrap());
        assert_eq!(Key::Start, Key::parse_char('S').unwrap());

        assert!(Key::parse_char('_').is_err());
    }
}
<|endoftext|>


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

#[macro_use]
extern crate habitat_butterfly;
#[macro_use]
extern crate habitat_butterfly_test as btest;

mod encryption;
mod rumor;

use habitat_butterfly::member::Health;

#[test]
fn two_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(2);
    net.mesh();
    assert_wait_for_health_of!(net, 0, 1, Health::Alive);
    assert_wait_for_health_of!(net, 1, 0, Health::Alive);

    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 1, 0, Health::Suspect);
    assert_wait_for_health_of!(net, 1, 0, Health::Confirmed);
}

#[test]
fn six_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(6);
    net.mesh();
    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}

#[test]
fn six_members_meshed_partition_one_node_from_another_node_remains_alive() {
    let mut net = btest::SwimNet::new(6);
    trace_it!(TEST_NET: net, "Mesh");
    net.mesh();
    net.block(0, 1);
    net.wait_for_rounds(2);
    assert_wait_for_health_of!(net, 1, Health::Alive);
}

#[test]
#[cfg_attr(feature = "ignore_inconsistent_tests", ignore)]
fn six_members_meshed_partition_half_of_nodes_from_each_other_both_sides_confirmed() {
    let mut net = btest::SwimNet::new(6);
    net.mesh();
    assert_wait_for_health_of!(net, 0, Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
}

#[test]
fn six_members_unmeshed_become_fully_meshed_via_gossip() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
}

#[test]
fn six_members_unmeshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}

#[test]
fn six_members_unmeshed_partition_and_rejoin_no_persistent_peers() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
    net.unpartition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
}

#[test]
fn six_members_unmeshed_partition_and_rejoin_persistent_peers() {
    let mut net = btest::SwimNet::new(6);
    net[0].member
          .write()
          .expect("Member lock is poisoned")
          .set_persistent();
    net[4].member
          .write()
          .expect("Member lock is poisoned")
          .set_persistent();
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
    net.unpartition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Alive);
}

#[test]
fn six_members_unmeshed_allows_graceful_departure() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    trace_it!(TEST: &net[0], "Departing");
    net[0].set_departed();
    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Departed);
}

#[test]
fn ten_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(10);
    net.mesh();
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}
<commit_msg>Remove the inconsistent test facility (part 2)<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[macro_use]
extern crate habitat_butterfly;
#[macro_use]
extern crate habitat_butterfly_test as btest;

mod encryption;
mod rumor;

use habitat_butterfly::member::Health;

#[test]
fn two_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(2);
    net.mesh();
    assert_wait_for_health_of!(net, 0, 1, Health::Alive);
    assert_wait_for_health_of!(net, 1, 0, Health::Alive);

    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 1, 0, Health::Suspect);
    assert_wait_for_health_of!(net, 1, 0, Health::Confirmed);
}

#[test]
fn six_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(6);
    net.mesh();
    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}

#[test]
fn six_members_meshed_partition_one_node_from_another_node_remains_alive() {
    let mut net = btest::SwimNet::new(6);
    trace_it!(TEST_NET: net, "Mesh");
    net.mesh();
    net.block(0, 1);
    net.wait_for_rounds(2);
    assert_wait_for_health_of!(net, 1, Health::Alive);
}

#[test]
fn six_members_meshed_partition_half_of_nodes_from_each_other_both_sides_confirmed() {
    let mut net = btest::SwimNet::new(6);
    net.mesh();
    assert_wait_for_health_of!(net, 0, Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
}

#[test]
fn six_members_unmeshed_become_fully_meshed_via_gossip() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
}

#[test]
fn six_members_unmeshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}

#[test]
fn six_members_unmeshed_partition_and_rejoin_no_persistent_peers() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
    net.unpartition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
}

#[test]
fn six_members_unmeshed_partition_and_rejoin_persistent_peers() {
    let mut net = btest::SwimNet::new(6);
    net[0].member
          .write()
          .expect("Member lock is poisoned")
          .set_persistent();
    net[4].member
          .write()
          .expect("Member lock is poisoned")
          .set_persistent();
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    net.partition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Confirmed);
    net.unpartition(0..3, 3..6);
    assert_wait_for_health_of!(net, [0..3, 3..6], Health::Alive);
}

#[test]
fn six_members_unmeshed_allows_graceful_departure() {
    let mut net = btest::SwimNet::new(6);
    net.connect(0, 1);
    net.connect(1, 2);
    net.connect(2, 3);
    net.connect(3, 4);
    net.connect(4, 5);
    assert_wait_for_health_of!(net, [0..6, 0..6], Health::Alive);
    trace_it!(TEST: &net[0], "Departing");
    net[0].set_departed();
    trace_it!(TEST: &net[0], "Paused");
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Departed);
}

#[test]
fn ten_members_meshed_confirm_one_member() {
    let mut net = btest::SwimNet::new(10);
    net.mesh();
    net[0].pause();
    assert_wait_for_health_of!(net, 0, Health::Confirmed);
}
<|endoftext|>


<commit_before>pub mod bound;
pub mod count;
pub mod predicates;

mod max;
mod sql_literal;

pub mod dsl {
    pub use super::count::{count, count_star};
    pub use super::max::max;
}

pub use self::dsl::*;
pub use self::sql_literal::SqlLiteral;

use query_builder::{QueryBuilder, BuildQueryResult};
use self::predicates::*;
use types::{Bool, NativeSqlType};

pub trait Expression: Sized {
    type SqlType: NativeSqlType;

    fn to_sql<T: QueryBuilder>(&self, out: &mut T) -> BuildQueryResult;

    fn eq<T: AsExpression<Self::SqlType>>(self, other: T) -> Eq<Self, T::Expression> {
        Eq::new(self, other.as_expression())
    }

    fn ne<T: AsExpression<Self::SqlType>>(self, other: T) -> NotEq<Self, T::Expression> {
        NotEq::new(self, other.as_expression())
    }

    fn gt<T: AsExpression<Self::SqlType>>(self, other: T) -> Gt<Self, T::Expression> {
        Gt::new(self, other.as_expression())
    }

    fn ge<T: AsExpression<Self::SqlType>>(self, other: T) -> GtEq<Self, T::Expression> {
        GtEq::new(self, other.as_expression())
    }

    fn lt<T: AsExpression<Self::SqlType>>(self, other: T) -> Lt<Self, T::Expression> {
        Lt::new(self, other.as_expression())
    }

    fn le<T: AsExpression<Self::SqlType>>(self, other: T) -> LtEq<Self, T::Expression> {
        LtEq::new(self, other.as_expression())
    }

    fn between<T: AsExpression<Self::SqlType>>(self, other: ::std::ops::Range<T>)
    -> Between<Self, And<T::Expression, T::Expression>> {
        Between::new(self, And::new(other.start.as_expression(), other.end.as_expression()))
    }

    fn not_between<T: AsExpression<Self::SqlType>>(self, other: ::std::ops::Range<T>)
    -> NotBetween<Self, And<T::Expression, T::Expression>> {
        NotBetween::new(self, And::new(other.start.as_expression(), other.end.as_expression()))
    }

    fn and<T: AsExpression<Bool>>(self, other: T) -> And<Self, T::Expression> {
        And::new(self, other.as_expression())
    }
}

pub trait AsExpression<T: NativeSqlType> {
    type Expression: Expression;

    fn as_expression(self) -> Self::Expression;
}

impl<T: Expression> AsExpression<T::SqlType> for T {
    type Expression = Self;

    fn as_expression(self) -> Self {
        self
    }
}

pub trait SelectableExpression<
    QS,
    Type: NativeSqlType = <Self as Expression>::SqlType,
>: Expression {
}

pub trait NonAggregate: Expression {
}
<commit_msg>Ensure `.and` can only be used when the left side is a bool expression<commit_after>pub mod bound;
pub mod count;
pub mod predicates;

mod max;
mod sql_literal;

pub mod dsl {
    pub use super::count::{count, count_star};
    pub use super::max::max;
}

pub use self::dsl::*;
pub use self::sql_literal::SqlLiteral;

use query_builder::{QueryBuilder, BuildQueryResult};
use self::predicates::*;
use types::{Bool, NativeSqlType};

pub trait Expression: Sized {
    type SqlType: NativeSqlType;

    fn to_sql<T: QueryBuilder>(&self, out: &mut T) -> BuildQueryResult;

    fn eq<T: AsExpression<Self::SqlType>>(self, other: T) -> Eq<Self, T::Expression> {
        Eq::new(self, other.as_expression())
    }

    fn ne<T: AsExpression<Self::SqlType>>(self, other: T) -> NotEq<Self, T::Expression> {
        NotEq::new(self, other.as_expression())
    }

    fn gt<T: AsExpression<Self::SqlType>>(self, other: T) -> Gt<Self, T::Expression> {
        Gt::new(self, other.as_expression())
    }

    fn ge<T: AsExpression<Self::SqlType>>(self, other: T) -> GtEq<Self, T::Expression> {
        GtEq::new(self, other.as_expression())
    }

    fn lt<T: AsExpression<Self::SqlType>>(self, other: T) -> Lt<Self, T::Expression> {
        Lt::new(self, other.as_expression())
    }

    fn le<T: AsExpression<Self::SqlType>>(self, other: T) -> LtEq<Self, T::Expression> {
        LtEq::new(self, other.as_expression())
    }

    fn between<T: AsExpression<Self::SqlType>>(self, other: ::std::ops::Range<T>)
    -> Between<Self, And<T::Expression, T::Expression>> {
        Between::new(self, And::new(other.start.as_expression(), other.end.as_expression()))
    }

    fn not_between<T: AsExpression<Self::SqlType>>(self, other: ::std::ops::Range<T>)
    -> NotBetween<Self, And<T::Expression, T::Expression>> {
        NotBetween::new(self, And::new(other.start.as_expression(), other.end.as_expression()))
    }

    fn and<T: AsExpression<Bool>>(self, other: T) -> And<Self::Expression, T::Expression> where
        Self: AsExpression<Bool>,
    {
        And::new(self.as_expression(), other.as_expression())
    }
}

pub trait AsExpression<T: NativeSqlType> {
    type Expression: Expression;

    fn as_expression(self) -> Self::Expression;
}

impl<T: Expression> AsExpression<T::SqlType> for T {
    type Expression = Self;

    fn as_expression(self) -> Self {
        self
    }
}

pub trait SelectableExpression<
    QS,
    Type: NativeSqlType = <Self as Expression>::SqlType,
>: Expression {
}

pub trait NonAggregate: Expression {
}
<|endoftext|>


<commit_before>use rand::{sample, Rng, SeedableRng, StdRng};
use std::time::Instant;
use std::collections::HashMap;
use rayon::prelude::*;
use statrs::distribution::{Distribution, Gamma, Normal};
use nalgebra::geometry::Point3 as Point;
use nalgebra::distance;
use std::sync::{Arc, Mutex};
use std::usize::MAX;
use std::f64;

pub mod names;
pub mod stars;
pub mod planets;

use resources::{fetch_resource, AstronomicalNamesResource};
use astronomicals::{hash, Galaxy};
use astronomicals::system::{System, SystemBuilder};
use game_config::GameConfig;
use generators::stars::StarGen;
use generators::names::NameGen;
use generators::planets::PlanetGen;
use astronomicals::planet::Planet;
use astronomicals::sector::Sector;
use entities::Faction;

/// A generator that can be explicitly seeded in order to the produce the same
/// stream of psuedo randomness each time.
pub trait SeedableGenerator {
    /// Reseed a generator with the given seed.
    fn reseed(&mut self, seed: u32);

    /// Create a new generator with the given seed.
    fn from_seed(seed: u32) -> Self;
}

/// A generator which can be trained by provided some training resource.
pub trait TrainableGenerator {
    type TrainRes;

    /// Train the generator with the given data.
    fn train(&mut self, &Self::TrainRes);
}

/// Generic mutable Generator, may modify the generator after generating an item.
pub trait MutGen: TrainableGenerator + SeedableGenerator {
    type GenItem;

    /// Generate a new item from the generator, can be None if the generator is empty etc.
    fn generate(&mut self) -> Option<Self::GenItem>;
}

/// Generic Generator, does not modify the generator instead uses provided random number generator.
pub trait Gen {
    type GenItem;

    /// Generate a new item from the generator, can be None if the generator is empty etc.
    fn generate<R: Rng>(&self, gen: &mut R) -> Option<Self::GenItem>;
}

/// Generate a galaxy with systems etc, will use the provided config to guide
/// the generation.
pub fn generate_galaxy(config: &GameConfig) -> Galaxy {
    let new_seed: &[_] = &[config.map_seed as usize];
    let mut rng: StdRng = SeedableRng::from_seed(new_seed);

    // Measure time for generation.
    let now = Instant::now();

    // Clusters are spaced uniformly, systems gaussian.
    let loc_x = Normal::new(0., config.system_spread).unwrap();
    let loc_y = Normal::new(0., config.system_spread).unwrap();
    let loc_z = Normal::new(0., config.system_spread / 10.).unwrap();

    // Generate system locations.
    let mut locations = vec![];
    for _ in 0..config.number_of_systems {
        locations.push(Point::new(
            loc_x.sample::<StdRng>(&mut rng),
            loc_y.sample::<StdRng>(&mut rng),
            loc_z.sample::<StdRng>(&mut rng),
        ))
    }

    // Create name generator to be shared mutably.
    let mut name_gen_unwraped = names::NameGen::from_seed(config.map_seed);
    name_gen_unwraped.train(&fetch_resource::<AstronomicalNamesResource>().unwrap());
    let name_gen = Arc::new(Mutex::new(name_gen_unwraped));

    // Create Star generator.
    let star_gen = stars::StarGen::new();

    // Create Planet generator.
    let planet_gen = planets::PlanetGen::new();

    // Generate systems for each cluster in parallel.
    // Fold will generate one vector per thread (per cluster), reduce will
    // combine them to the final result.
    let systems = locations
        .into_par_iter()
        .fold(
            || Vec::<System>::new(),
            |mut systems: Vec<System>, location| {
                // Generate system
                systems.push(generate_system(
                    location,
                    name_gen.clone(),
                    &star_gen,
                    &planet_gen,
                ));
                systems
            },
        )
        .reduce(
            || Vec::<System>::new(),
            |mut systems, subsystems| {
                systems.extend(subsystems);
                systems
            },
        );

    info!(
        "Generated new galaxy containing: {} systems and {} planets taking {} ms",
        systems.len(),
        systems
            .iter()
            .fold(0, |acc, ref sys| acc + sys.satelites.len(),),
        ((now.elapsed().as_secs() * 1_000) + (now.elapsed().subsec_nanos() / 1_000_000) as u64)
    );
    debug!("Generated System examples:");
    for system in systems.iter().take(10) {
        debug!("{:#?}\n", system);
    }

    Galaxy::new(into_sectors(config, name_gen, systems))
}

/// Generate a new star system using the given generators and a location as seed.
pub fn generate_system(
    location: Point<f64>,
    name_gen: Arc<Mutex<NameGen>>,
    star_gen: &StarGen,
    planet_gen: &PlanetGen,
) -> System {
    // Calculate hash.
    let hash = hash(location);
    let seed: &[_] = &[hash as usize];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let star = star_gen.generate(&mut rng).unwrap();

    // Unwrap and lock name generator as it is mutated by generation.
    let mut name_gen_unwraped = name_gen.lock().unwrap();
    name_gen_unwraped.reseed(hash as u32);

    // TODO: Replace constant in config.
    let num_planets = Gamma::new(1., 0.5)
        .unwrap()
        .sample::<StdRng>(&mut rng)
        .round() as u32;

    // Fallback to planet name: Unnamed if no name could be generated.
    let satelites: Vec<Planet> = (0..num_planets)
        .map(|_| {
            let mut builder = planet_gen.generate(&mut rng).unwrap();
            let mass = builder.mass.unwrap();
            let surface_temperature =
                Planet::calculate_surface_temperature(builder.orbit_distance.unwrap(), &star);
            builder
                .name(
                    name_gen_unwraped
                        .generate()
                        .unwrap_or(String::from("Unnamed")),
                )
                .surface_temperature(surface_temperature)
                .planet_type(Planet::predict_type(surface_temperature, mass))
                .build()
                .unwrap()
        })
        .collect();

    // System name is the same as one random planet.
    // Fallback to: Unnamed System if it contains no planets and no name could
    // be generated.
    let name = match rng.choose(&satelites) {
        Some(planet) => planet.name.clone(),
        None => name_gen_unwraped
            .generate()
            .unwrap_or(String::from("Unnamed")),
    } + " System";

    SystemBuilder::default()
        .location(location)
        .name(name)
        .star(star)
        .satelites(satelites)
        .build()
        .unwrap()
}

/// Split the systems in to a set number of clusters using K-means.
fn into_sectors(
    config: &GameConfig,
    name_gen: Arc<Mutex<NameGen>>,
    systems: Vec<System>,
) -> Vec<Sector> {
    // Measure time for generation.
    let now = Instant::now();

    info!("Simulating expansion for initial sectors...");
    let seed: &[_] = &[hash as usize];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    // Split data into two sets if using approximation
    let mut idx = 0;
    let (cluster_set, rest): (Vec<System>, Vec<System>) = systems.into_iter().partition(|_| {
        idx += 1;
        idx < config.num_approximation_systems || !config.sector_approximation
    });

    // System to cluster_id mapping
    let mut cluster_map = cluster_set
        .into_par_iter()
        .fold(
            || HashMap::<System, usize>::new(),
            |mut partial_map: HashMap<System, usize>, system| {
                // Generate system
                partial_map.insert(system, 0);
                partial_map
            },
        )
        .reduce(
            || HashMap::<System, usize>::new(),
            |mut cluster_map, partial_map| {
                cluster_map.extend(partial_map);
                cluster_map
            },
        );

    // Setup initial centroids
    let mut centroids = sample(&mut rng, cluster_map.iter(), config.number_of_sectors)
        .into_iter()
        .map(|(system, _)| system.location.clone())
        .collect::<Vec<_>>();

    // Run K means until convergence, i.e until no reassignments
    let mut has_assigned = true;
    while has_assigned {
        let wrapped_assigned = Mutex::new(false);

        // Assign to closest centroid
        cluster_map.par_iter_mut().for_each(|(system, cluster_id)| {
            let mut closest_cluster = *cluster_id;
            let mut closest_distance = distance(&system.location, &centroids[*cluster_id]);
            for i in 0..centroids.len() {
                let distance = distance(&system.location, &centroids[i]);
                if distance < closest_distance {
                    *wrapped_assigned.lock().unwrap() = true;
                    closest_cluster = i;
                    closest_distance = distance;
                }
            }
            *cluster_id = closest_cluster;
        });

        has_assigned = *wrapped_assigned.lock().unwrap();

        // Calculate new centroids
        centroids
            .par_iter_mut()
            .enumerate()
            .for_each(|(id, centroid)| {
                let mut count = 0.;
                let mut new_centroid = Point::origin();
                for (system, _) in cluster_map.iter().filter(|&(_, c_id)| *c_id == id) {
                    new_centroid += system.location.coords;
                    count += 1.;
                }
                new_centroid *= 1. / count;
                *centroid = new_centroid;
            });
    }

    // Setup cluster vectors
    let mut sector_vecs =
        (0..config.number_of_sectors).fold(Vec::<Vec<System>>::new(), |mut sectors, _| {
            sectors.push(vec![]);
            sectors
        });

    // Map systems to final cluster
    for (system, id) in cluster_map.into_iter() {
        sector_vecs[id].push(system);
    }

    // Assign remaining systems to closest centroid if any left
    rest.into_iter().for_each(|system| {
        let mut closest_cluster = 0;
        let mut closest_distance = f64::MAX;
        for i in 0..centroids.len() {
            let distance = distance(&system.location, &centroids[i]);
            if distance < closest_distance {
                closest_cluster = i;
                closest_distance = distance;
            }
        }
        sector_vecs[closest_cluster].push(system);
    });

    // Unwrap and lock name generator as it is mutated by generation.
    let mut name_gen_unwraped = name_gen.lock().unwrap();
    name_gen_unwraped.reseed(config.number_of_sectors as u32);

    // Create sector for each cluster
    let sectors = sector_vecs
        .into_iter()
        .map(|systems| Sector {
            systems: systems,
            name: name_gen_unwraped
                .generate()
                .unwrap_or(String::from("Unnamed")) + " Sector",
            faction: Faction::random_faction(&mut rng),
        })
        .collect::<Vec<Sector>>();

    info!(
        "Mapped galaxy into {} sectors of {} systems, avg size: {},
          max size {}, min size {}, taking {} ms \n
          Sectors include: {} Cartel, {} Empire, {} Federation, {} Independent",
        sectors.len(),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + sec.systems.len()),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + sec.systems.len()) / sectors.len(),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc.max(sec.systems.len())),
        sectors
            .iter()
            .fold(MAX, |acc, ref sec| acc.min(sec.systems.len())),
        ((now.elapsed().as_secs() * 1_000) + (now.elapsed().subsec_nanos() / 1_000_000) as u64),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Cartel => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Empire => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Federation => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Independent => 1,
                _ => 0,
            })
    );

    sectors
}
<commit_msg>Change distribution to given more planets, fixes #60 (#72)<commit_after>use rand::{sample, Rng, SeedableRng, StdRng};
use std::time::Instant;
use std::collections::HashMap;
use rayon::prelude::*;
use statrs::distribution::{Distribution, Gamma, Normal};
use nalgebra::geometry::Point3 as Point;
use nalgebra::distance;
use std::sync::{Arc, Mutex};
use std::usize::MAX;
use std::f64;

pub mod names;
pub mod stars;
pub mod planets;

use resources::{fetch_resource, AstronomicalNamesResource};
use astronomicals::{hash, Galaxy};
use astronomicals::system::{System, SystemBuilder};
use game_config::GameConfig;
use generators::stars::StarGen;
use generators::names::NameGen;
use generators::planets::PlanetGen;
use astronomicals::planet::Planet;
use astronomicals::sector::Sector;
use entities::Faction;

/// A generator that can be explicitly seeded in order to the produce the same
/// stream of psuedo randomness each time.
pub trait SeedableGenerator {
    /// Reseed a generator with the given seed.
    fn reseed(&mut self, seed: u32);

    /// Create a new generator with the given seed.
    fn from_seed(seed: u32) -> Self;
}

/// A generator which can be trained by provided some training resource.
pub trait TrainableGenerator {
    type TrainRes;

    /// Train the generator with the given data.
    fn train(&mut self, &Self::TrainRes);
}

/// Generic mutable Generator, may modify the generator after generating an item.
pub trait MutGen: TrainableGenerator + SeedableGenerator {
    type GenItem;

    /// Generate a new item from the generator, can be None if the generator is empty etc.
    fn generate(&mut self) -> Option<Self::GenItem>;
}

/// Generic Generator, does not modify the generator instead uses provided random number generator.
pub trait Gen {
    type GenItem;

    /// Generate a new item from the generator, can be None if the generator is empty etc.
    fn generate<R: Rng>(&self, gen: &mut R) -> Option<Self::GenItem>;
}

/// Generate a galaxy with systems etc, will use the provided config to guide
/// the generation.
pub fn generate_galaxy(config: &GameConfig) -> Galaxy {
    let new_seed: &[_] = &[config.map_seed as usize];
    let mut rng: StdRng = SeedableRng::from_seed(new_seed);

    // Measure time for generation.
    let now = Instant::now();

    // Clusters are spaced uniformly, systems gaussian.
    let loc_x = Normal::new(0., config.system_spread).unwrap();
    let loc_y = Normal::new(0., config.system_spread).unwrap();
    let loc_z = Normal::new(0., config.system_spread / 10.).unwrap();

    // Generate system locations.
    let mut locations = vec![];
    for _ in 0..config.number_of_systems {
        locations.push(Point::new(
            loc_x.sample::<StdRng>(&mut rng),
            loc_y.sample::<StdRng>(&mut rng),
            loc_z.sample::<StdRng>(&mut rng),
        ))
    }

    // Create name generator to be shared mutably.
    let mut name_gen_unwraped = names::NameGen::from_seed(config.map_seed);
    name_gen_unwraped.train(&fetch_resource::<AstronomicalNamesResource>().unwrap());
    let name_gen = Arc::new(Mutex::new(name_gen_unwraped));

    // Create Star generator.
    let star_gen = stars::StarGen::new();

    // Create Planet generator.
    let planet_gen = planets::PlanetGen::new();

    // Generate systems for each cluster in parallel.
    // Fold will generate one vector per thread (per cluster), reduce will
    // combine them to the final result.
    let systems = locations
        .into_par_iter()
        .fold(
            || Vec::<System>::new(),
            |mut systems: Vec<System>, location| {
                // Generate system
                systems.push(generate_system(
                    location,
                    name_gen.clone(),
                    &star_gen,
                    &planet_gen,
                ));
                systems
            },
        )
        .reduce(
            || Vec::<System>::new(),
            |mut systems, subsystems| {
                systems.extend(subsystems);
                systems
            },
        );

    info!(
        "Generated new galaxy containing: {} systems and {} planets taking {} ms",
        systems.len(),
        systems
            .iter()
            .fold(0, |acc, ref sys| acc + sys.satelites.len(),),
        ((now.elapsed().as_secs() * 1_000) + (now.elapsed().subsec_nanos() / 1_000_000) as u64)
    );
    debug!("Generated System examples:");
    for system in systems.iter().take(10) {
        debug!("{:#?}\n", system);
    }

    Galaxy::new(into_sectors(config, name_gen, systems))
}

/// Generate a new star system using the given generators and a location as seed.
pub fn generate_system(
    location: Point<f64>,
    name_gen: Arc<Mutex<NameGen>>,
    star_gen: &StarGen,
    planet_gen: &PlanetGen,
) -> System {
    // Calculate hash.
    let hash = hash(location);
    let seed: &[_] = &[hash as usize];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    let star = star_gen.generate(&mut rng).unwrap();

    // Unwrap and lock name generator as it is mutated by generation.
    let mut name_gen_unwraped = name_gen.lock().unwrap();
    name_gen_unwraped.reseed(hash as u32);

    // TODO: Replace constant in config.
    let num_planets = Gamma::new(3.5, 1.)
        .unwrap()
        .sample::<StdRng>(&mut rng)
        .round() as u32;

    // Fallback to planet name: Unnamed if no name could be generated.
    let satelites: Vec<Planet> = (0..num_planets)
        .map(|_| {
            let mut builder = planet_gen.generate(&mut rng).unwrap();
            let mass = builder.mass.unwrap();
            let surface_temperature =
                Planet::calculate_surface_temperature(builder.orbit_distance.unwrap(), &star);
            builder
                .name(
                    name_gen_unwraped
                        .generate()
                        .unwrap_or(String::from("Unnamed")),
                )
                .surface_temperature(surface_temperature)
                .planet_type(Planet::predict_type(surface_temperature, mass))
                .build()
                .unwrap()
        })
        .collect();

    // System name is the same as one random planet.
    // Fallback to: Unnamed System if it contains no planets and no name could
    // be generated.
    let name = match rng.choose(&satelites) {
        Some(planet) => planet.name.clone(),
        None => name_gen_unwraped
            .generate()
            .unwrap_or(String::from("Unnamed")),
    } + " System";

    SystemBuilder::default()
        .location(location)
        .name(name)
        .star(star)
        .satelites(satelites)
        .build()
        .unwrap()
}

/// Split the systems in to a set number of clusters using K-means.
fn into_sectors(
    config: &GameConfig,
    name_gen: Arc<Mutex<NameGen>>,
    systems: Vec<System>,
) -> Vec<Sector> {
    // Measure time for generation.
    let now = Instant::now();

    info!("Simulating expansion for initial sectors...");
    let seed: &[_] = &[hash as usize];
    let mut rng: StdRng = SeedableRng::from_seed(seed);

    // Split data into two sets if using approximation
    let mut idx = 0;
    let (cluster_set, rest): (Vec<System>, Vec<System>) = systems.into_iter().partition(|_| {
        idx += 1;
        idx < config.num_approximation_systems || !config.sector_approximation
    });

    // System to cluster_id mapping
    let mut cluster_map = cluster_set
        .into_par_iter()
        .fold(
            || HashMap::<System, usize>::new(),
            |mut partial_map: HashMap<System, usize>, system| {
                // Generate system
                partial_map.insert(system, 0);
                partial_map
            },
        )
        .reduce(
            || HashMap::<System, usize>::new(),
            |mut cluster_map, partial_map| {
                cluster_map.extend(partial_map);
                cluster_map
            },
        );

    // Setup initial centroids
    let mut centroids = sample(&mut rng, cluster_map.iter(), config.number_of_sectors)
        .into_iter()
        .map(|(system, _)| system.location.clone())
        .collect::<Vec<_>>();

    // Run K means until convergence, i.e until no reassignments
    let mut has_assigned = true;
    while has_assigned {
        let wrapped_assigned = Mutex::new(false);

        // Assign to closest centroid
        cluster_map.par_iter_mut().for_each(|(system, cluster_id)| {
            let mut closest_cluster = *cluster_id;
            let mut closest_distance = distance(&system.location, &centroids[*cluster_id]);
            for i in 0..centroids.len() {
                let distance = distance(&system.location, &centroids[i]);
                if distance < closest_distance {
                    *wrapped_assigned.lock().unwrap() = true;
                    closest_cluster = i;
                    closest_distance = distance;
                }
            }
            *cluster_id = closest_cluster;
        });

        has_assigned = *wrapped_assigned.lock().unwrap();

        // Calculate new centroids
        centroids
            .par_iter_mut()
            .enumerate()
            .for_each(|(id, centroid)| {
                let mut count = 0.;
                let mut new_centroid = Point::origin();
                for (system, _) in cluster_map.iter().filter(|&(_, c_id)| *c_id == id) {
                    new_centroid += system.location.coords;
                    count += 1.;
                }
                new_centroid *= 1. / count;
                *centroid = new_centroid;
            });
    }

    // Setup cluster vectors
    let mut sector_vecs =
        (0..config.number_of_sectors).fold(Vec::<Vec<System>>::new(), |mut sectors, _| {
            sectors.push(vec![]);
            sectors
        });

    // Map systems to final cluster
    for (system, id) in cluster_map.into_iter() {
        sector_vecs[id].push(system);
    }

    // Assign remaining systems to closest centroid if any left
    rest.into_iter().for_each(|system| {
        let mut closest_cluster = 0;
        let mut closest_distance = f64::MAX;
        for i in 0..centroids.len() {
            let distance = distance(&system.location, &centroids[i]);
            if distance < closest_distance {
                closest_cluster = i;
                closest_distance = distance;
            }
        }
        sector_vecs[closest_cluster].push(system);
    });

    // Unwrap and lock name generator as it is mutated by generation.
    let mut name_gen_unwraped = name_gen.lock().unwrap();
    name_gen_unwraped.reseed(config.number_of_sectors as u32);

    // Create sector for each cluster
    let sectors = sector_vecs
        .into_iter()
        .map(|systems| Sector {
            systems: systems,
            name: name_gen_unwraped
                .generate()
                .unwrap_or(String::from("Unnamed")) + " Sector",
            faction: Faction::random_faction(&mut rng),
        })
        .collect::<Vec<Sector>>();

    info!(
        "Mapped galaxy into {} sectors of {} systems, avg size: {},
          max size {}, min size {}, taking {} ms \n
          Sectors include: {} Cartel, {} Empire, {} Federation, {} Independent",
        sectors.len(),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + sec.systems.len()),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + sec.systems.len()) / sectors.len(),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc.max(sec.systems.len())),
        sectors
            .iter()
            .fold(MAX, |acc, ref sec| acc.min(sec.systems.len())),
        ((now.elapsed().as_secs() * 1_000) + (now.elapsed().subsec_nanos() / 1_000_000) as u64),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Cartel => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Empire => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Federation => 1,
                _ => 0,
            }),
        sectors
            .iter()
            .fold(0, |acc, ref sec| acc + match sec.faction {
                Faction::Independent => 1,
                _ => 0,
            })
    );

    sectors
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// TODO: Doc comments, unexport interrupts from main thread

use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use mio::event::Evented;
use mio::unix::{EventedFd, UnixReady};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel;

use gpio::sysfs;

pub use gpio::sysfs::Direction;
pub use gpio::{Level, Trigger};

quick_error! {
    #[derive(Debug)]
/// Errors that can occur while working with interrupts.
    pub enum Error {
/// Time out.
        TimeOut { description("interrupt polling timed out while waiting for a trigger") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Sysfs error.
        Sysfs(err: sysfs::Error) { description(err.description()) from() }
/// IO error while communicating with the interrupt polling thread.
        SendIo(err: io::Error) { description(err.description()) }
/// Disconnected while sending a control message to the interrupt polling thread.
        SendDisconnected { description("the receiving half of the channel has disconnected") }
    }
}

impl<T> From<channel::SendError<T>> for Error {
    fn from(err: channel::SendError<T>) -> Error {
        match err {
            channel::SendError::Io(e) => Error::SendIo(e),
            channel::SendError::Disconnected(_) => Error::SendDisconnected,
        }
    }
}

/// Result type returned from methods that can have `rppal::gpio::interrupt::Error`s.
pub type Result<T> = result::Result<T, Error>;

const TOKEN_RX: usize = 1000;

struct InterruptBase {
    pin: u8,
    trigger: Trigger,
    sysfs_value: File,
}

impl InterruptBase {
    fn new(pin: u8, trigger: Trigger) -> Result<InterruptBase> {
        // Export the GPIO pin so we can configure it through sysfs, set its mode to
        // input, and set the trigger type.
        sysfs::export(pin)?;
        sysfs::set_direction(pin, Direction::In)?;
        sysfs::set_edge(pin, trigger)?;

        Ok(InterruptBase {
            pin: pin,
            trigger: trigger,
            sysfs_value: sysfs::open_value(pin)?,
        })
    }

    fn level(&mut self) -> Result<Level> {
        let mut buffer = [0; 1];
        self.sysfs_value.read(&mut buffer)?;
        self.sysfs_value.seek(SeekFrom::Start(0))?;

        match &buffer {
            b"0" => Ok(Level::Low),
            _ => Ok(Level::High),
        }
    }
}

impl Drop for InterruptBase {
    fn drop(&mut self) {
        sysfs::unexport(self.pin).ok();
    }
}

impl Evented for InterruptBase {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).deregister(poll)
    }
}

pub struct Interrupt {
    base: InterruptBase,
    poll: Poll,
    events: Events,
}

impl Interrupt {
    pub fn new(pin: u8, trigger: Trigger) -> Result<Interrupt> {
        let mut base = InterruptBase::new(pin, trigger)?;
        let poll = Poll::new()?;
        let events = Events::with_capacity(1);

        base.level()?;
        poll.register(
            &base,
            Token(0),
            Ready::readable() | UnixReady::error(),
            PollOpt::edge(),
        )?;

        Ok(Interrupt {
            base: base,
            poll: poll,
            events: events,
        })
    }

    pub fn poll(&mut self, timeout: Option<Duration>) -> Result<Level> {
        // Loop until we get the event we're waiting for, or a timeout occurs
        loop {
            self.poll.poll(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if self.events.is_empty() {
                return Err(Error::TimeOut);
            }

            for event in &self.events {
                if event.token() == Token(0) && event.readiness().is_readable()
                    && UnixReady::from(event.readiness()).is_error()
                {
                    return Ok(self.base.level()?);
                }
            }
        }
    }
}

pub struct AsyncInterrupt {
    base: InterruptBase,
    callback: Box<FnMut(Level) + Send>,
}

impl AsyncInterrupt {
    pub fn new<C>(pin: u8, trigger: Trigger, callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        Ok(AsyncInterrupt {
            base: InterruptBase::new(pin, trigger)?,
            callback: Box::new(callback),
        })
    }

    pub fn callback(&mut self, level: Level) {
        (self.callback)(level);
    }

    pub fn level(&mut self) -> Result<Level> {
        Ok(self.base.level()?)
    }
}

enum ControlMsg {
    Add(u8, AsyncInterrupt),
    Remove(u8),
    Stop,
}

pub struct EventLoop {
    tx: Option<channel::Sender<ControlMsg>>,
}

impl EventLoop {
    pub fn new() -> EventLoop {
        EventLoop { tx: None }
    }

    fn spawn_pollthread(&mut self) -> &channel::Sender<ControlMsg> {
        let (tx, rx) = channel::channel();

        thread::spawn(move || {
            let mut interrupts = HashMap::new();
            let poll = Poll::new().expect("unable to create Poll instance");
            let mut events = Events::with_capacity(1024);

            poll.register(&rx, Token(TOKEN_RX), Ready::readable(), PollOpt::edge())
                .expect("unable to register Receiver");

            loop {
                poll.poll(&mut events, None).expect("unable to poll events");

                for event in &events {
                    if event.token() == Token(TOKEN_RX) {
                        loop {
                            match rx.try_recv() {
                                Ok(ControlMsg::Add(pin, mut interrupt)) => {
                                    interrupt
                                        .base
                                        .level()
                                        .expect("unable to read Interrupt level");
                                    poll.register(
                                        &interrupt.base,
                                        Token(pin as usize),
                                        Ready::readable() | UnixReady::error(),
                                        PollOpt::edge(),
                                    ).expect("unable to register Interrupt");
                                    interrupts.insert(pin as usize, interrupt);
                                }
                                Ok(ControlMsg::Remove(pin)) => {
                                    if let Some(interrupt) = interrupts.get(&(pin as usize)) {
                                        poll.deregister(&interrupt.base)
                                            .expect("unable to deregister Interrupt");
                                    }

                                    interrupts.remove(&(pin as usize));
                                }
                                Ok(ControlMsg::Stop) => {
                                    return;
                                }
                                Err(TryRecvError::Disconnected) => {
                                    return;
                                }
                                Err(TryRecvError::Empty) => {
                                    break;
                                }
                            }
                        }
                    } else if let Some(interrupt) = interrupts.get_mut(&event.token().0) {
                        if event.readiness().is_readable()
                            && UnixReady::from(event.readiness()).is_error()
                        {
                            let interrupt_value = interrupt.base.level().expect("unable to read Interrupt level");

                            interrupt.callback(interrupt_value);
                        }
                    }
                }
            }
        });

        self.tx = Some(tx);
        self.tx.as_ref().unwrap()
    }

    pub fn set_interrupt<C>(&mut self, pin: u8, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        // Only spawn a thread for interrupt polling if we're actually using interrupts.
        let tx = if let Some(ref tx) = self.tx {
            tx
        } else {
            self.spawn_pollthread()
        };

        tx.send(ControlMsg::Add(
            pin,
            AsyncInterrupt::new(pin, trigger, callback)?,
        ))?;

        Ok(())
    }

    pub fn clear_interrupt(&self, pin: u8) -> Result<()> {
        if let Some(ref tx) = self.tx {
            tx.send(ControlMsg::Remove(pin))?;
        }

        Ok(())
    }

    pub fn stop(&mut self) -> Result<()> {
        if let Some(ref tx) = self.tx {
            tx.send(ControlMsg::Stop)?;
        }

        Ok(())
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        self.stop().ok();
    }
}
<commit_msg>Add missing 'static requirement<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// TODO: Doc comments, unexport interrupts from main thread

use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::{Read, Seek, SeekFrom};
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use mio::event::Evented;
use mio::unix::{EventedFd, UnixReady};
use mio::{Events, Poll, PollOpt, Ready, Token};
use mio_extras::channel;

use gpio::sysfs;

pub use gpio::sysfs::Direction;
pub use gpio::{Level, Trigger};

quick_error! {
    #[derive(Debug)]
/// Errors that can occur while working with interrupts.
    pub enum Error {
/// Time out.
        TimeOut { description("interrupt polling timed out while waiting for a trigger") }
/// IO error.
        Io(err: io::Error) { description(err.description()) from() }
/// Sysfs error.
        Sysfs(err: sysfs::Error) { description(err.description()) from() }
/// IO error while communicating with the interrupt polling thread.
        SendIo(err: io::Error) { description(err.description()) }
/// Disconnected while sending a control message to the interrupt polling thread.
        SendDisconnected { description("the receiving half of the channel has disconnected") }
    }
}

impl<T> From<channel::SendError<T>> for Error {
    fn from(err: channel::SendError<T>) -> Error {
        match err {
            channel::SendError::Io(e) => Error::SendIo(e),
            channel::SendError::Disconnected(_) => Error::SendDisconnected,
        }
    }
}

/// Result type returned from methods that can have `rppal::gpio::interrupt::Error`s.
pub type Result<T> = result::Result<T, Error>;

const TOKEN_RX: usize = 1000;

struct InterruptBase {
    pin: u8,
    trigger: Trigger,
    sysfs_value: File,
}

impl InterruptBase {
    fn new(pin: u8, trigger: Trigger) -> Result<InterruptBase> {
        // Export the GPIO pin so we can configure it through sysfs, set its mode to
        // input, and set the trigger type.
        sysfs::export(pin)?;
        sysfs::set_direction(pin, Direction::In)?;
        sysfs::set_edge(pin, trigger)?;

        Ok(InterruptBase {
            pin: pin,
            trigger: trigger,
            sysfs_value: sysfs::open_value(pin)?,
        })
    }

    fn level(&mut self) -> Result<Level> {
        let mut buffer = [0; 1];
        self.sysfs_value.read(&mut buffer)?;
        self.sysfs_value.seek(SeekFrom::Start(0))?;

        match &buffer {
            b"0" => Ok(Level::Low),
            _ => Ok(Level::High),
        }
    }
}

impl Drop for InterruptBase {
    fn drop(&mut self) {
        sysfs::unexport(self.pin).ok();
    }
}

impl Evented for InterruptBase {
    fn register(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).register(poll, token, interest, opts)
    }

    fn reregister(
        &self,
        poll: &Poll,
        token: Token,
        interest: Ready,
        opts: PollOpt,
    ) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).reregister(poll, token, interest, opts)
    }

    fn deregister(&self, poll: &Poll) -> io::Result<()> {
        EventedFd(&self.sysfs_value.as_raw_fd()).deregister(poll)
    }
}

pub struct Interrupt {
    base: InterruptBase,
    poll: Poll,
    events: Events,
}

impl Interrupt {
    pub fn new(pin: u8, trigger: Trigger) -> Result<Interrupt> {
        let mut base = InterruptBase::new(pin, trigger)?;
        let poll = Poll::new()?;
        let events = Events::with_capacity(1);

        base.level()?;
        poll.register(
            &base,
            Token(0),
            Ready::readable() | UnixReady::error(),
            PollOpt::edge(),
        )?;

        Ok(Interrupt {
            base: base,
            poll: poll,
            events: events,
        })
    }

    pub fn poll(&mut self, timeout: Option<Duration>) -> Result<Level> {
        // Loop until we get the event we're waiting for, or a timeout occurs
        loop {
            self.poll.poll(&mut self.events, timeout)?;

            // No events means a timeout occurred
            if self.events.is_empty() {
                return Err(Error::TimeOut);
            }

            for event in &self.events {
                if event.token() == Token(0) && event.readiness().is_readable()
                    && UnixReady::from(event.readiness()).is_error()
                {
                    return Ok(self.base.level()?);
                }
            }
        }
    }
}

pub struct AsyncInterrupt {
    base: InterruptBase,
    callback: Box<FnMut(Level) + Send + 'static>,
}

impl AsyncInterrupt {
    pub fn new<C>(pin: u8, trigger: Trigger, callback: C) -> Result<AsyncInterrupt>
    where
        C: FnMut(Level) + Send + 'static,
    {
        Ok(AsyncInterrupt {
            base: InterruptBase::new(pin, trigger)?,
            callback: Box::new(callback),
        })
    }

    pub fn callback(&mut self, level: Level) {
        (self.callback)(level);
    }

    pub fn level(&mut self) -> Result<Level> {
        Ok(self.base.level()?)
    }
}

enum ControlMsg {
    Add(u8, AsyncInterrupt),
    Remove(u8),
    Stop,
}

pub struct EventLoop {
    tx: Option<channel::Sender<ControlMsg>>,
}

impl EventLoop {
    pub fn new() -> EventLoop {
        EventLoop { tx: None }
    }

    fn spawn_pollthread(&mut self) -> &channel::Sender<ControlMsg> {
        let (tx, rx) = channel::channel();

        thread::spawn(move || {
            let mut interrupts = HashMap::new();
            let poll = Poll::new().expect("unable to create Poll instance");
            let mut events = Events::with_capacity(1024);

            poll.register(&rx, Token(TOKEN_RX), Ready::readable(), PollOpt::edge())
                .expect("unable to register Receiver");

            loop {
                poll.poll(&mut events, None).expect("unable to poll events");

                for event in &events {
                    if event.token() == Token(TOKEN_RX) {
                        loop {
                            match rx.try_recv() {
                                Ok(ControlMsg::Add(pin, mut interrupt)) => {
                                    interrupt
                                        .base
                                        .level()
                                        .expect("unable to read Interrupt level");
                                    poll.register(
                                        &interrupt.base,
                                        Token(pin as usize),
                                        Ready::readable() | UnixReady::error(),
                                        PollOpt::edge(),
                                    ).expect("unable to register Interrupt");
                                    interrupts.insert(pin as usize, interrupt);
                                }
                                Ok(ControlMsg::Remove(pin)) => {
                                    if let Some(interrupt) = interrupts.get(&(pin as usize)) {
                                        poll.deregister(&interrupt.base)
                                            .expect("unable to deregister Interrupt");
                                    }

                                    interrupts.remove(&(pin as usize));
                                }
                                Ok(ControlMsg::Stop) => {
                                    return;
                                }
                                Err(TryRecvError::Disconnected) => {
                                    return;
                                }
                                Err(TryRecvError::Empty) => {
                                    break;
                                }
                            }
                        }
                    } else if let Some(interrupt) = interrupts.get_mut(&event.token().0) {
                        if event.readiness().is_readable()
                            && UnixReady::from(event.readiness()).is_error()
                        {
                            let interrupt_value = interrupt.base.level().expect("unable to read Interrupt level");

                            interrupt.callback(interrupt_value);
                        }
                    }
                }
            }
        });

        self.tx = Some(tx);
        self.tx.as_ref().unwrap()
    }

    pub fn set_interrupt<C>(&mut self, pin: u8, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        // Only spawn a thread for interrupt polling if we're actually using interrupts.
        let tx = if let Some(ref tx) = self.tx {
            tx
        } else {
            self.spawn_pollthread()
        };

        tx.send(ControlMsg::Add(
            pin,
            AsyncInterrupt::new(pin, trigger, callback)?,
        ))?;

        Ok(())
    }

    pub fn clear_interrupt(&self, pin: u8) -> Result<()> {
        if let Some(ref tx) = self.tx {
            tx.send(ControlMsg::Remove(pin))?;
        }

        Ok(())
    }

    pub fn stop(&mut self) -> Result<()> {
        if let Some(ref tx) = self.tx {
            tx.send(ControlMsg::Stop)?;
        }

        Ok(())
    }
}

impl Drop for EventLoop {
    fn drop(&mut self) {
        self.stop().ok();
    }
}
<|endoftext|>


<commit_before>use ra_ide_db::RootDatabase;
use ra_syntax::{
    ast::{self, AstNode, NameOwner},
    TextSize,
};
use stdx::format_to;
use test_utils::tested_by;

use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};

// Assist add_from_impl_for_enum
//
// Adds a From impl for an enum variant with one tuple field
//
// ```
// enum A { <|>One(u32) }
// ```
// ->
// ```
// enum A { One(u32) }
//
// impl From<u32> for A {
//     fn from(v: u32) -> Self {
//         A::One(v)
//     }
// }
// ```
pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
    let variant_name = variant.name()?;
    let enum_name = variant.parent_enum().name()?;
    let field_list = match variant.kind() {
        ast::StructKind::Tuple(field_list) => field_list,
        _ => return None,
    };
    if field_list.fields().count() != 1 {
        return None;
    }
    let field_type = field_list.fields().next()?.type_ref()?;
    let path = match field_type {
        ast::TypeRef::PathType(p) => p,
        _ => return None,
    };

    if existing_from_impl(&ctx.sema, &variant).is_some() {
        tested_by!(test_add_from_impl_already_exists);
        return None;
    }

    let target = variant.syntax().text_range();
    acc.add(
        AssistId("add_from_impl_for_enum"),
        "Add From impl for this enum variant",
        target,
        |edit| {
            let start_offset = variant.parent_enum().syntax().text_range().end();
            let mut buf = String::new();
            format_to!(
                buf,
                r#"

impl From<{0}> for {1} {{
    fn from(v: {0}) -> Self {{
        {1}::{2}(v)
    }}
}}"#,
                path.syntax(),
                enum_name,
                variant_name
            );
            edit.insert(start_offset, buf);
            edit.set_cursor(start_offset + TextSize::of("\n\n"));
        },
    )
}

fn existing_from_impl(
    sema: &'_ hir::Semantics<'_, RootDatabase>,
    variant: &ast::EnumVariant,
) -> Option<()> {
    let variant = sema.to_def(variant)?;
    let enum_ = variant.parent_enum(sema.db);
    let krate = enum_.module(sema.db).krate();

    let from_trait = FamousDefs(sema, krate).core_convert_From()?;

    let enum_type = enum_.ty(sema.db);

    let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);

    if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
        Some(())
    } else {
        None
    }
}

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

    use crate::tests::{check_assist, check_assist_not_applicable};
    use test_utils::covers;

    #[test]
    fn test_add_from_impl_for_enum() {
        check_assist(
            add_from_impl_for_enum,
            "enum A { <|>One(u32) }",
            r#"enum A { One(u32) }

<|>impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}"#,
        );
    }

    #[test]
    fn test_add_from_impl_for_enum_complicated_path() {
        check_assist(
            add_from_impl_for_enum,
            "enum A { <|>One(foo::bar::baz::Boo) }",
            r#"enum A { One(foo::bar::baz::Boo) }

<|>impl From<foo::bar::baz::Boo> for A {
    fn from(v: foo::bar::baz::Boo) -> Self {
        A::One(v)
    }
}"#,
        );
    }

    fn check_not_applicable(ra_fixture: &str) {
        let fixture =
            format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
        check_assist_not_applicable(add_from_impl_for_enum, &fixture)
    }

    #[test]
    fn test_add_from_impl_no_element() {
        check_not_applicable("enum A { <|>One }");
    }

    #[test]
    fn test_add_from_impl_more_than_one_element_in_tuple() {
        check_not_applicable("enum A { <|>One(u32, String) }");
    }

    #[test]
    fn test_add_from_impl_struct_variant() {
        check_not_applicable("enum A { <|>One { x: u32 } }");
    }

    #[test]
    fn test_add_from_impl_already_exists() {
        covers!(test_add_from_impl_already_exists);
        check_not_applicable(
            r#"
enum A { <|>One(u32), }

impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}
"#,
        );
    }

    #[test]
    fn test_add_from_impl_different_variant_impl_exists() {
        check_assist(
            add_from_impl_for_enum,
            r#"enum A { <|>One(u32), Two(String), }

impl From<String> for A {
    fn from(v: String) -> Self {
        A::Two(v)
    }
}

pub trait From<T> {
    fn from(T) -> Self;
}"#,
            r#"enum A { One(u32), Two(String), }

<|>impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}

impl From<String> for A {
    fn from(v: String) -> Self {
        A::Two(v)
    }
}

pub trait From<T> {
    fn from(T) -> Self;
}"#,
        );
    }
}
<commit_msg>Add From should not move the cursor<commit_after>use ra_ide_db::RootDatabase;
use ra_syntax::ast::{self, AstNode, NameOwner};
use stdx::format_to;
use test_utils::tested_by;

use crate::{utils::FamousDefs, AssistContext, AssistId, Assists};

// Assist add_from_impl_for_enum
//
// Adds a From impl for an enum variant with one tuple field
//
// ```
// enum A { <|>One(u32) }
// ```
// ->
// ```
// enum A { One(u32) }
//
// impl From<u32> for A {
//     fn from(v: u32) -> Self {
//         A::One(v)
//     }
// }
// ```
pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let variant = ctx.find_node_at_offset::<ast::EnumVariant>()?;
    let variant_name = variant.name()?;
    let enum_name = variant.parent_enum().name()?;
    let field_list = match variant.kind() {
        ast::StructKind::Tuple(field_list) => field_list,
        _ => return None,
    };
    if field_list.fields().count() != 1 {
        return None;
    }
    let field_type = field_list.fields().next()?.type_ref()?;
    let path = match field_type {
        ast::TypeRef::PathType(p) => p,
        _ => return None,
    };

    if existing_from_impl(&ctx.sema, &variant).is_some() {
        tested_by!(test_add_from_impl_already_exists);
        return None;
    }

    let target = variant.syntax().text_range();
    acc.add(
        AssistId("add_from_impl_for_enum"),
        "Add From impl for this enum variant",
        target,
        |edit| {
            let start_offset = variant.parent_enum().syntax().text_range().end();
            let mut buf = String::new();
            format_to!(
                buf,
                r#"

impl From<{0}> for {1} {{
    fn from(v: {0}) -> Self {{
        {1}::{2}(v)
    }}
}}"#,
                path.syntax(),
                enum_name,
                variant_name
            );
            edit.insert(start_offset, buf);
        },
    )
}

fn existing_from_impl(
    sema: &'_ hir::Semantics<'_, RootDatabase>,
    variant: &ast::EnumVariant,
) -> Option<()> {
    let variant = sema.to_def(variant)?;
    let enum_ = variant.parent_enum(sema.db);
    let krate = enum_.module(sema.db).krate();

    let from_trait = FamousDefs(sema, krate).core_convert_From()?;

    let enum_type = enum_.ty(sema.db);

    let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);

    if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
        Some(())
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use test_utils::covers;

    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn test_add_from_impl_for_enum() {
        check_assist(
            add_from_impl_for_enum,
            "enum A { <|>One(u32) }",
            r#"enum A { <|>One(u32) }

impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}"#,
        );
    }

    #[test]
    fn test_add_from_impl_for_enum_complicated_path() {
        check_assist(
            add_from_impl_for_enum,
            r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
            r#"enum A { <|>One(foo::bar::baz::Boo) }

impl From<foo::bar::baz::Boo> for A {
    fn from(v: foo::bar::baz::Boo) -> Self {
        A::One(v)
    }
}"#,
        );
    }

    fn check_not_applicable(ra_fixture: &str) {
        let fixture =
            format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
        check_assist_not_applicable(add_from_impl_for_enum, &fixture)
    }

    #[test]
    fn test_add_from_impl_no_element() {
        check_not_applicable("enum A { <|>One }");
    }

    #[test]
    fn test_add_from_impl_more_than_one_element_in_tuple() {
        check_not_applicable("enum A { <|>One(u32, String) }");
    }

    #[test]
    fn test_add_from_impl_struct_variant() {
        check_not_applicable("enum A { <|>One { x: u32 } }");
    }

    #[test]
    fn test_add_from_impl_already_exists() {
        covers!(test_add_from_impl_already_exists);
        check_not_applicable(
            r#"
enum A { <|>One(u32), }

impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}
"#,
        );
    }

    #[test]
    fn test_add_from_impl_different_variant_impl_exists() {
        check_assist(
            add_from_impl_for_enum,
            r#"enum A { <|>One(u32), Two(String), }

impl From<String> for A {
    fn from(v: String) -> Self {
        A::Two(v)
    }
}

pub trait From<T> {
    fn from(T) -> Self;
}"#,
            r#"enum A { <|>One(u32), Two(String), }

impl From<u32> for A {
    fn from(v: u32) -> Self {
        A::One(v)
    }
}

impl From<String> for A {
    fn from(v: String) -> Self {
        A::Two(v)
    }
}

pub trait From<T> {
    fn from(T) -> Self;
}"#,
        );
    }
}
<|endoftext|>