<commit_before>#![allow(non_upper_case_globals)]

//! Types defined by Linux-PAM
//!
//! This modules contains struct and enum definitions used by `pam-sys`.

use pam_macros::pam_enum;
use bitflags::bitflags;

bitflags! {
    pub struct PamAuthenticateFlag: i32 {
        /// Authentication service should not generate any messages
        const Silent = pam_sys::PAM_SILENT;
        /// The authentication service should return AUTH_ERROR
        /// if the user has a null authentication token
        /// (used by pam_authenticate{,_secondary}())
        const DisallowNullAuthTok = pam_sys::PAM_DISALLOW_NULL_AUTHTOK;
    }
}

/// The Linux-PAM return values
#[pam_enum]
pub enum PamReturnCode {
    /// System error
    System_Err,

    /// Successful function return
    Success,

    /// dlopen() failure when dynamically loading a service module
    Open_Err,

    /// Symbol not found
    Symbol_Err,

    /// Error in service module
    Service_Err,

    /// Memory buffer error
    Buf_Err,

    /// Permission denied
    Perm_Denied,

    /// Authentication failure
    Auth_Err,

    /// Can not access authentication data due to insufficient credentials
    Cred_Insufficient,

    /// Underlying authentication service can not retrieve authentication information
    Authinfo_Unavail,

    /// User not known to the underlying authentication module
    User_Unknown,

    /// An authentication service has maintained a retry count which has been reached.
    /// No further retries should be attempted
    MaxTries,

    /// New authentication token required.
    /// This is normally returned if the machine security policies require
    /// that the password should be changed beccause the password is NULL or it has aged
    New_Authtok_Reqd,

    /// User account has expired
    Acct_Expired,

    /// Can not make/remove an entry for the specified session
    Session_Err,

    /// Underlying authentication service can not retrieve user credentials unavailable
    Cred_Unavail,

    /// User credentials expired
    Cred_Expired,

    /// Failure setting user credentials
    Cred_Err,

    /// No module specific data is present
    No_Module_Data,

    /// Conversation error
    Conv_Err,

    /// Authentication token manipulation error
    AuthTok_Err,

    /// Authentication information cannot be recovered
    AuthTok_Recovery_Err,

    /// Authentication token lock busy
    AuthTok_Lock_Busy,

    /// Authentication token aging disabled
    AuthTok_Disable_Aging,

    /// Preliminary check by password service
    Try_Again,

    /// Ignore underlying account module regardless of whether
    /// the control flag is required, optional, or sufficient
    Ignore,

    /// Critical error (?module fail now request)
    AuthTok_Expired,

    /// user's authentication token has expired
    Abort,

    /// module is not known
    Module_Unknown,

    /// Bad item passed to pam_*_item()
    Bad_Item,

    /// conversation function is event driven and data is not available yet
    Conv_Again,

    /// please call this function again to complete authentication stack.
    /// Before calling again as isize, verify that conversation is completed
    Incomplete,
}

impl std::fmt::Display for PamReturnCode {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM flags
#[pam_enum]
pub enum PamFlag {
    /// Default value, if no specific flags should be passed
    None = 0,

    /// Authentication service should not generate any messages
    Silent,

    /// The authentication service should return AUTH_ERROR
    /// if the user has a null authentication token
    /// (used by pam_authenticate{,_secondary}())
    Disallow_Null_AuthTok,

    /// Set user credentials for an authentication service
    /// (used for pam_setcred())
    Establish_Cred,

    /// Delete user credentials associated with an authentication service
    /// (used for pam_setcred())
    Delete_Cred,

    /// Reinitialize user credentials
    /// (used for pam_setcred())
    Reinitialize_Cred,

    /// Extend lifetime of user credentials
    /// (used for pam_setcred())
    Refresh_Cred,

    /// The password service should only update those passwords that have aged.
    /// If this flag is not passed, the password service should update all passwords.
    /// (used by pam_chauthtok)
    Change_Expired_AuthTok,

    /// The password service should update passwords Note: PAM_PRELIM_CHECK
    /// and PAM_UPDATE_AUTHTOK cannot both be set simultaneously!
    Update_AuthTok,

    /// The following two flags are for use across the Linux-PAM/module
    /// interface only. The Application is not permitted to use these
    /// tokens.
    ///
    /// The password service should only perform preliminary checks.  No
    /// passwords should be updated.
    Prelim_Check,
}

impl std::fmt::Display for PamFlag {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM item types
///
/// These defines are used by `pam_set_item()` `and pam_get_item()`.
/// Please check the spec which are allowed for use by applications
/// and which are only allowed for use by modules.
#[pam_enum]
pub enum PamItemType {
    /// The service name
    Service,

    /// The user name
    User,

    /// The tty name
    TTY,

    /// The remote host name
    RHost,

    /// The pam_conv structure
    Conv,

    /// The authentication token (password)
    AuthTok,

    /// The old authentication token
    OldAuthTok,

    /// The remote user name
    RUser,

    /// the prompt for getting a username Linux-PAM extensions
    User_Prompt,

    /// app supplied function to override failure delays
    Fail_Delay,

    /// X display name
    XDisplay,

    /// X server authentication data
    XAuthData,

    /// The type for pam_get_authtok
    AuthTok_Type,
}

impl std::fmt::Display for PamItemType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM message styles
#[pam_enum]
pub enum PamMessageStyle {
    Prompt_Echo_On,
    Prompt_Echo_Off,
    Error_Msg,
    Text_Info,
}

impl std::fmt::Display for PamMessageStyle {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}
<commit_msg>fix: remove temporary enum<commit_after>#![allow(non_upper_case_globals)]

//! Types defined by Linux-PAM
//!
//! This modules contains struct and enum definitions used by `pam-sys`.

use pam_macros::pam_enum;

/// The Linux-PAM return values
#[pam_enum]
pub enum PamReturnCode {
    /// System error
    System_Err,

    /// Successful function return
    Success,

    /// dlopen() failure when dynamically loading a service module
    Open_Err,

    /// Symbol not found
    Symbol_Err,

    /// Error in service module
    Service_Err,

    /// Memory buffer error
    Buf_Err,

    /// Permission denied
    Perm_Denied,

    /// Authentication failure
    Auth_Err,

    /// Can not access authentication data due to insufficient credentials
    Cred_Insufficient,

    /// Underlying authentication service can not retrieve authentication information
    Authinfo_Unavail,

    /// User not known to the underlying authentication module
    User_Unknown,

    /// An authentication service has maintained a retry count which has been reached.
    /// No further retries should be attempted
    MaxTries,

    /// New authentication token required.
    /// This is normally returned if the machine security policies require
    /// that the password should be changed beccause the password is NULL or it has aged
    New_Authtok_Reqd,

    /// User account has expired
    Acct_Expired,

    /// Can not make/remove an entry for the specified session
    Session_Err,

    /// Underlying authentication service can not retrieve user credentials unavailable
    Cred_Unavail,

    /// User credentials expired
    Cred_Expired,

    /// Failure setting user credentials
    Cred_Err,

    /// No module specific data is present
    No_Module_Data,

    /// Conversation error
    Conv_Err,

    /// Authentication token manipulation error
    AuthTok_Err,

    /// Authentication information cannot be recovered
    AuthTok_Recovery_Err,

    /// Authentication token lock busy
    AuthTok_Lock_Busy,

    /// Authentication token aging disabled
    AuthTok_Disable_Aging,

    /// Preliminary check by password service
    Try_Again,

    /// Ignore underlying account module regardless of whether
    /// the control flag is required, optional, or sufficient
    Ignore,

    /// Critical error (?module fail now request)
    AuthTok_Expired,

    /// user's authentication token has expired
    Abort,

    /// module is not known
    Module_Unknown,

    /// Bad item passed to pam_*_item()
    Bad_Item,

    /// conversation function is event driven and data is not available yet
    Conv_Again,

    /// please call this function again to complete authentication stack.
    /// Before calling again as isize, verify that conversation is completed
    Incomplete,
}

impl std::fmt::Display for PamReturnCode {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM flags
#[pam_enum]
pub enum PamFlag {
    /// Default value, if no specific flags should be passed
    None = 0,

    /// Authentication service should not generate any messages
    Silent,

    /// The authentication service should return AUTH_ERROR
    /// if the user has a null authentication token
    /// (used by pam_authenticate{,_secondary}())
    Disallow_Null_AuthTok,

    /// Set user credentials for an authentication service
    /// (used for pam_setcred())
    Establish_Cred,

    /// Delete user credentials associated with an authentication service
    /// (used for pam_setcred())
    Delete_Cred,

    /// Reinitialize user credentials
    /// (used for pam_setcred())
    Reinitialize_Cred,

    /// Extend lifetime of user credentials
    /// (used for pam_setcred())
    Refresh_Cred,

    /// The password service should only update those passwords that have aged.
    /// If this flag is not passed, the password service should update all passwords.
    /// (used by pam_chauthtok)
    Change_Expired_AuthTok,

    /// The password service should update passwords Note: PAM_PRELIM_CHECK
    /// and PAM_UPDATE_AUTHTOK cannot both be set simultaneously!
    Update_AuthTok,

    /// The following two flags are for use across the Linux-PAM/module
    /// interface only. The Application is not permitted to use these
    /// tokens.
    ///
    /// The password service should only perform preliminary checks.  No
    /// passwords should be updated.
    Prelim_Check,
}

impl std::fmt::Display for PamFlag {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM item types
///
/// These defines are used by `pam_set_item()` `and pam_get_item()`.
/// Please check the spec which are allowed for use by applications
/// and which are only allowed for use by modules.
#[pam_enum]
pub enum PamItemType {
    /// The service name
    Service,

    /// The user name
    User,

    /// The tty name
    TTY,

    /// The remote host name
    RHost,

    /// The pam_conv structure
    Conv,

    /// The authentication token (password)
    AuthTok,

    /// The old authentication token
    OldAuthTok,

    /// The remote user name
    RUser,

    /// the prompt for getting a username Linux-PAM extensions
    User_Prompt,

    /// app supplied function to override failure delays
    Fail_Delay,

    /// X display name
    XDisplay,

    /// X server authentication data
    XAuthData,

    /// The type for pam_get_authtok
    AuthTok_Type,
}

impl std::fmt::Display for PamItemType {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}

/// The Linux-PAM message styles
#[pam_enum]
pub enum PamMessageStyle {
    Prompt_Echo_On,
    Prompt_Echo_Off,
    Error_Msg,
    Text_Info,
}

impl std::fmt::Display for PamMessageStyle {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        f.write_str(&format!("{:?} ({})", self, *self as i32))
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::error::Error;
use super::{
    Dimension,
};

/// An error related to array shape or layout.
#[derive(Clone)]
pub struct ShapeError {
    // we want to be able to change this representation later
    repr: ErrorKind,
}

impl ShapeError {
    /// Return the `ErrorKind` of this error.
    #[inline]
    pub fn kind(&self) -> ErrorKind {
        self.repr
    }
}

/// Error code for an error related to array shape or layout.
///
/// This enumeration is not exhaustive. The representation of the enum
/// is not guaranteed.
#[derive(Copy, Clone, Debug)]
#[repr(u64)]
pub enum ErrorKind {
    /// incompatible shape
    IncompatibleShape,
    /// incompatible memory layout
    IncompatibleLayout,
    /// the shape does not fit inside type limits
    RangeLimited,
    /// stride leads to out of bounds indexing
    OutOfBounds,
    /// stride leads to aliasing array elements
    Unsupported,
    #[doc(hidden)]
    __Incomplete,
}

#[inline(always)]
pub fn from_kind(k: ErrorKind) -> ShapeError {
    ShapeError {
        repr: k
    }
}

impl PartialEq for ErrorKind {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        *self as u64 == *rhs as u64
    }
}

impl PartialEq for ShapeError {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        self.repr == rhs.repr
    }
}

impl Error for ShapeError {
    fn description(&self) -> &str {
        match self.kind() {
            ErrorKind::IncompatibleShape => "incompatible shapes",
            ErrorKind::IncompatibleLayout => "incompatible memory layout",
            ErrorKind::RangeLimited => "the shape does not fit in type limits",
            ErrorKind::OutOfBounds => "stride leads to out of bounds indexing",
            ErrorKind::Unsupported => "stride leads to aliasing array elements",
            ErrorKind::__Incomplete => "this error variant is not in use",
        }
    }
}

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

impl fmt::Debug for ShapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ShapeError {:?}: {}", self.kind(), self.description())
    }
}

pub fn incompatible_shapes<D, E>(_a: &D, _b: &E) -> ShapeError
    where D: Dimension,
          E: Dimension
{
    from_kind(ErrorKind::IncompatibleShape)
}
<commit_msg>Rm repr() for ErrorKind<commit_after>use std::fmt;
use std::error::Error;
use super::{
    Dimension,
};

/// An error related to array shape or layout.
#[derive(Clone)]
pub struct ShapeError {
    // we want to be able to change this representation later
    repr: ErrorKind,
}

impl ShapeError {
    /// Return the `ErrorKind` of this error.
    #[inline]
    pub fn kind(&self) -> ErrorKind {
        self.repr
    }
}

/// Error code for an error related to array shape or layout.
///
/// This enumeration is not exhaustive. The representation of the enum
/// is not guaranteed.
#[derive(Copy, Clone, Debug)]
pub enum ErrorKind {
    /// incompatible shape
    IncompatibleShape,
    /// incompatible memory layout
    IncompatibleLayout,
    /// the shape does not fit inside type limits
    RangeLimited,
    /// stride leads to out of bounds indexing
    OutOfBounds,
    /// stride leads to aliasing array elements
    Unsupported,
    #[doc(hidden)]
    __Incomplete,
}

#[inline(always)]
pub fn from_kind(k: ErrorKind) -> ShapeError {
    ShapeError {
        repr: k
    }
}

impl PartialEq for ErrorKind {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        *self as u8 == *rhs as u8
    }
}

impl PartialEq for ShapeError {
    #[inline(always)]
    fn eq(&self, rhs: &Self) -> bool {
        self.repr == rhs.repr
    }
}

impl Error for ShapeError {
    fn description(&self) -> &str {
        match self.kind() {
            ErrorKind::IncompatibleShape => "incompatible shapes",
            ErrorKind::IncompatibleLayout => "incompatible memory layout",
            ErrorKind::RangeLimited => "the shape does not fit in type limits",
            ErrorKind::OutOfBounds => "stride leads to out of bounds indexing",
            ErrorKind::Unsupported => "stride leads to aliasing array elements",
            ErrorKind::__Incomplete => "this error variant is not in use",
        }
    }
}

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

impl fmt::Debug for ShapeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ShapeError {:?}: {}", self.kind(), self.description())
    }
}

pub fn incompatible_shapes<D, E>(_a: &D, _b: &E) -> ShapeError
    where D: Dimension,
          E: Dimension
{
    from_kind(ErrorKind::IncompatibleShape)
}
<|endoftext|>


<commit_before>// Copyright 2016 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rand::{Rand, Rng};
use num_traits::cast;

use structure::*;

use angle::Rad;
use approx::ApproxEq;
use quaternion::Quaternion;
use num::BaseFloat;

/// A set of [Euler angles] representing a rotation in three-dimensional space.
///
/// This type is marked as `#[repr(C)]`.
///
/// The axis rotation sequence is XYZ. That is, the rotation is first around
/// the X axis, then the Y axis, and lastly the Z axis (using intrinsic
/// rotations). Since all three rotation axes are used, the angles are
/// Tait–Bryan angles rather than proper Euler angles.
///
/// # Ranges
///
/// - x: [-pi, pi]
/// - y: [-pi/2, pi/2]
/// - z: [-pi, pi]
///
/// # Defining rotations using Euler angles
///
/// Note that while [Euler angles] are intuitive to define, they are prone to
/// [gimbal lock] and are challenging to interpolate between. Instead we
/// recommend that you convert them to a more robust representation, such as a
/// quaternion or or rotation matrix. To this end, `From<Euler<A>>` conversions
/// are provided for the following types:
///
/// - [`Basis3`](struct.Basis3.html)
/// - [`Matrix3`](struct.Matrix3.html)
/// - [`Matrix4`](struct.Matrix4.html)
/// - [`Quaternion`](struct.Quaternion.html)
///
/// For example, to define a quaternion that applies the following:
///
/// 1. a 90° rotation around the _x_ axis
/// 2. a 45° rotation around the _y_ axis
/// 3. a 15° rotation around the _z_ axis
///
/// you can use the following code:
///
/// ```
/// use cgmath::{Deg, Euler, Quaternion};
///
/// let rotation = Quaternion::from(Euler {
///     x: Deg(90.0),
///     y: Deg(45.0),
///     z: Deg(15.0),
/// });
/// ```
///
/// [Euler angles]: https://en.wikipedia.org/wiki/Euler_angles
/// [gimbal lock]: https://en.wikipedia.org/wiki/Gimbal_lock#Gimbal_lock_in_applied_mathematics
/// [convert]: #defining-rotations-using-euler-angles
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Euler<A: Angle> {
    /// The angle to apply around the _x_ axis. Also known at the _pitch_.
    pub x: A,
    /// The angle to apply around the _y_ axis. Also known at the _yaw_.
    pub y: A,
    /// The angle to apply around the _z_ axis. Also known at the _roll_.
    pub z: A,
}

impl<A: Angle> Euler<A> {
    /// Construct a set of euler angles.
    ///
    /// # Arguments
    ///
    /// * `x` - The angle to apply around the _x_ axis. Also known at the _pitch_.
    /// * `y` - The angle to apply around the _y_ axis. Also known at the _yaw_.
    /// * `z` - The angle to apply around the _z_ axis. Also known at the _roll_.
    pub fn new(x: A, y: A, z: A) -> Euler<A> {
        Euler { x: x, y: y, z: z }
    }
}

impl<S: BaseFloat> From<Quaternion<S>> for Euler<Rad<S>> {
    fn from(src: Quaternion<S>) -> Euler<Rad<S>> {
        let sig: S = cast(0.499).unwrap();
        let two: S = cast(2).unwrap();
        let one: S = cast(1).unwrap();

        let (qw, qx, qy, qz) = (src.s, src.v.x, src.v.y, src.v.z);
        let (sqw, sqx, sqy, sqz) = (qw * qw, qx * qx, qy * qy, qz * qz);

        let unit = sqx + sqz + sqy + sqw;
        let test = qx * qz + qy * qw;

        // We set x to zero and z to the value, but the other way would work too.
        if test > sig * unit {
            // x + z = 2 * atan(x / w)
            Euler {
                x: Rad::zero(),
                y: Rad::turn_div_4(),
                z: Rad::atan2(qx, qw) * two,
            }
        } else if test < -sig * unit {
            // x - z = 2 * atan(x / w)
            Euler {
                x: Rad::zero(),
                y: -Rad::turn_div_4(),
                z: -Rad::atan2(qx, qw) * two,
            }
        } else {
            // Using the quat-to-matrix equation from either
            // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
            // or equation 15 on page 7 of
            // http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
            // to fill in the equations on page A-2 of the NASA document gives the below.
            Euler {
                x: Rad::atan2(two * (-qy * qz + qx * qw), one - two * (sqx + sqy)),
                y: Rad::asin(two * (qx * qz + qy * qw)),
                z: Rad::atan2(two * (-qx * qy + qz * qw), one - two * (sqy + sqz)),
            }
        }
    }
}

impl<A: Angle> ApproxEq for Euler<A> {
    type Epsilon = A::Epsilon;

    #[inline]
    fn default_epsilon() -> A::Epsilon {
        A::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> A::Epsilon {
        A::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        A::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
        A::relative_eq(&self.x, &other.x, epsilon, max_relative) &&
        A::relative_eq(&self.y, &other.y, epsilon, max_relative) &&
        A::relative_eq(&self.z, &other.z, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: A::Epsilon, max_ulps: u32) -> bool {
        A::ulps_eq(&self.x, &other.x, epsilon, max_ulps) &&
        A::ulps_eq(&self.y, &other.y, epsilon, max_ulps) &&
        A::ulps_eq(&self.z, &other.z, epsilon, max_ulps)
    }
}

impl<A: Angle + Rand> Rand for Euler<A> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Euler<A> {
        Euler { x: rng.gen(), y: rng.gen(), z: rng.gen() }
    }
}
<commit_msg>or or -> or a.<commit_after>// Copyright 2016 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use rand::{Rand, Rng};
use num_traits::cast;

use structure::*;

use angle::Rad;
use approx::ApproxEq;
use quaternion::Quaternion;
use num::BaseFloat;

/// A set of [Euler angles] representing a rotation in three-dimensional space.
///
/// This type is marked as `#[repr(C)]`.
///
/// The axis rotation sequence is XYZ. That is, the rotation is first around
/// the X axis, then the Y axis, and lastly the Z axis (using intrinsic
/// rotations). Since all three rotation axes are used, the angles are
/// Tait–Bryan angles rather than proper Euler angles.
///
/// # Ranges
///
/// - x: [-pi, pi]
/// - y: [-pi/2, pi/2]
/// - z: [-pi, pi]
///
/// # Defining rotations using Euler angles
///
/// Note that while [Euler angles] are intuitive to define, they are prone to
/// [gimbal lock] and are challenging to interpolate between. Instead we
/// recommend that you convert them to a more robust representation, such as a
/// quaternion or a rotation matrix. To this end, `From<Euler<A>>` conversions
/// are provided for the following types:
///
/// - [`Basis3`](struct.Basis3.html)
/// - [`Matrix3`](struct.Matrix3.html)
/// - [`Matrix4`](struct.Matrix4.html)
/// - [`Quaternion`](struct.Quaternion.html)
///
/// For example, to define a quaternion that applies the following:
///
/// 1. a 90° rotation around the _x_ axis
/// 2. a 45° rotation around the _y_ axis
/// 3. a 15° rotation around the _z_ axis
///
/// you can use the following code:
///
/// ```
/// use cgmath::{Deg, Euler, Quaternion};
///
/// let rotation = Quaternion::from(Euler {
///     x: Deg(90.0),
///     y: Deg(45.0),
///     z: Deg(15.0),
/// });
/// ```
///
/// [Euler angles]: https://en.wikipedia.org/wiki/Euler_angles
/// [gimbal lock]: https://en.wikipedia.org/wiki/Gimbal_lock#Gimbal_lock_in_applied_mathematics
/// [convert]: #defining-rotations-using-euler-angles
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Euler<A: Angle> {
    /// The angle to apply around the _x_ axis. Also known at the _pitch_.
    pub x: A,
    /// The angle to apply around the _y_ axis. Also known at the _yaw_.
    pub y: A,
    /// The angle to apply around the _z_ axis. Also known at the _roll_.
    pub z: A,
}

impl<A: Angle> Euler<A> {
    /// Construct a set of euler angles.
    ///
    /// # Arguments
    ///
    /// * `x` - The angle to apply around the _x_ axis. Also known at the _pitch_.
    /// * `y` - The angle to apply around the _y_ axis. Also known at the _yaw_.
    /// * `z` - The angle to apply around the _z_ axis. Also known at the _roll_.
    pub fn new(x: A, y: A, z: A) -> Euler<A> {
        Euler { x: x, y: y, z: z }
    }
}

impl<S: BaseFloat> From<Quaternion<S>> for Euler<Rad<S>> {
    fn from(src: Quaternion<S>) -> Euler<Rad<S>> {
        let sig: S = cast(0.499).unwrap();
        let two: S = cast(2).unwrap();
        let one: S = cast(1).unwrap();

        let (qw, qx, qy, qz) = (src.s, src.v.x, src.v.y, src.v.z);
        let (sqw, sqx, sqy, sqz) = (qw * qw, qx * qx, qy * qy, qz * qz);

        let unit = sqx + sqz + sqy + sqw;
        let test = qx * qz + qy * qw;

        // We set x to zero and z to the value, but the other way would work too.
        if test > sig * unit {
            // x + z = 2 * atan(x / w)
            Euler {
                x: Rad::zero(),
                y: Rad::turn_div_4(),
                z: Rad::atan2(qx, qw) * two,
            }
        } else if test < -sig * unit {
            // x - z = 2 * atan(x / w)
            Euler {
                x: Rad::zero(),
                y: -Rad::turn_div_4(),
                z: -Rad::atan2(qx, qw) * two,
            }
        } else {
            // Using the quat-to-matrix equation from either
            // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
            // or equation 15 on page 7 of
            // http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
            // to fill in the equations on page A-2 of the NASA document gives the below.
            Euler {
                x: Rad::atan2(two * (-qy * qz + qx * qw), one - two * (sqx + sqy)),
                y: Rad::asin(two * (qx * qz + qy * qw)),
                z: Rad::atan2(two * (-qx * qy + qz * qw), one - two * (sqy + sqz)),
            }
        }
    }
}

impl<A: Angle> ApproxEq for Euler<A> {
    type Epsilon = A::Epsilon;

    #[inline]
    fn default_epsilon() -> A::Epsilon {
        A::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> A::Epsilon {
        A::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        A::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
        A::relative_eq(&self.x, &other.x, epsilon, max_relative) &&
        A::relative_eq(&self.y, &other.y, epsilon, max_relative) &&
        A::relative_eq(&self.z, &other.z, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: A::Epsilon, max_ulps: u32) -> bool {
        A::ulps_eq(&self.x, &other.x, epsilon, max_ulps) &&
        A::ulps_eq(&self.y, &other.y, epsilon, max_ulps) &&
        A::ulps_eq(&self.z, &other.z, epsilon, max_ulps)
    }
}

impl<A: Angle + Rand> Rand for Euler<A> {
    #[inline]
    fn rand<R: Rng>(rng: &mut R) -> Euler<A> {
        Euler { x: rng.gen(), y: rng.gen(), z: rng.gen() }
    }
}
<|endoftext|>


<commit_before>use clap::{value_t, App, Arg};
use futures::*;
use log::info;

use rdkafka::config::ClientConfig;
use rdkafka::message::OwnedHeaders;
use rdkafka::producer::{FutureProducer, FutureRecord};
use rdkafka::util::get_rdkafka_version;

use crate::example_utils::setup_logger;

mod example_utils;

async fn produce(brokers: &str, topic_name: &str) {
    let producer: FutureProducer = ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // This loop is non blocking: all messages will be sent one after the other, without waiting
    // for the results.
    let futures = (0..5)
        .map(|i| {
            // The send operation on the topic returns a future, that will be completed once the
            // result or failure from Kafka will be received.
            producer
                .send(
                    FutureRecord::to(topic_name)
                        .payload(&format!("Message {}", i))
                        .key(&format!("Key {}", i))
                        .headers(OwnedHeaders::new().add("header_key", "header_value")),
                    0,
                )
                .map(move |delivery_status| {
                    // This will be executed onw the result is received
                    info!("Delivery status for message {} received", i);
                    delivery_status
                })
        })
        .collect::<Vec<_>>();

    // This loop will wait until all delivery statuses have been received received.
    for future in futures {
        info!("Future completed. Result: {:?}", future.await);
    }
}

#[tokio::main]
async fn main() {
    let matches = App::new("producer example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("Simple command line producer")
        .arg(
            Arg::with_name("brokers")
                .short("b")
                .long("brokers")
                .help("Broker list in kafka format")
                .takes_value(true)
                .default_value("localhost:9092"),
        )
        .arg(
            Arg::with_name("log-conf")
                .long("log-conf")
                .help("Configure the logging format (example: 'rdkafka=trace')")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("topic")
                .short("t")
                .long("topic")
                .help("Destination topic")
                .takes_value(true)
                .required(true),
        )
        .get_matches();

    setup_logger(true, matches.value_of("log-conf"));

    let (version_n, version_s) = get_rdkafka_version();
    info!("rd_kafka_version: 0x{:08x}, {}", version_n, version_s);

    let topic = matches.value_of("topic").unwrap();
    let brokers = matches.value_of("brokers").unwrap();

    produce(brokers, topic).await;
}
<commit_msg>Remove unused import in simple_producer example<commit_after>use clap::{App, Arg};
use futures::*;
use log::info;

use rdkafka::config::ClientConfig;
use rdkafka::message::OwnedHeaders;
use rdkafka::producer::{FutureProducer, FutureRecord};
use rdkafka::util::get_rdkafka_version;

use crate::example_utils::setup_logger;

mod example_utils;

async fn produce(brokers: &str, topic_name: &str) {
    let producer: FutureProducer = ClientConfig::new()
        .set("bootstrap.servers", brokers)
        .set("message.timeout.ms", "5000")
        .create()
        .expect("Producer creation error");

    // This loop is non blocking: all messages will be sent one after the other, without waiting
    // for the results.
    let futures = (0..5)
        .map(|i| {
            // The send operation on the topic returns a future, that will be completed once the
            // result or failure from Kafka will be received.
            producer
                .send(
                    FutureRecord::to(topic_name)
                        .payload(&format!("Message {}", i))
                        .key(&format!("Key {}", i))
                        .headers(OwnedHeaders::new().add("header_key", "header_value")),
                    0,
                )
                .map(move |delivery_status| {
                    // This will be executed onw the result is received
                    info!("Delivery status for message {} received", i);
                    delivery_status
                })
        })
        .collect::<Vec<_>>();

    // This loop will wait until all delivery statuses have been received received.
    for future in futures {
        info!("Future completed. Result: {:?}", future.await);
    }
}

#[tokio::main]
async fn main() {
    let matches = App::new("producer example")
        .version(option_env!("CARGO_PKG_VERSION").unwrap_or(""))
        .about("Simple command line producer")
        .arg(
            Arg::with_name("brokers")
                .short("b")
                .long("brokers")
                .help("Broker list in kafka format")
                .takes_value(true)
                .default_value("localhost:9092"),
        )
        .arg(
            Arg::with_name("log-conf")
                .long("log-conf")
                .help("Configure the logging format (example: 'rdkafka=trace')")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("topic")
                .short("t")
                .long("topic")
                .help("Destination topic")
                .takes_value(true)
                .required(true),
        )
        .get_matches();

    setup_logger(true, matches.value_of("log-conf"));

    let (version_n, version_s) = get_rdkafka_version();
    info!("rd_kafka_version: 0x{:08x}, {}", version_n, version_s);

    let topic = matches.value_of("topic").unwrap();
    let brokers = matches.value_of("brokers").unwrap();

    produce(brokers, topic).await;
}
<|endoftext|>


<commit_before>use std::fmt;
use irccase::IrcAsciiExt;

use parse::IrcMsg;
use watchers::base::{Bundler, BundlerTrigger};
use event::IrcEvent;

pub type JoinResult = Result<JoinSuccess, JoinError>;

trait ChannelTargeted {
    fn get_channel(&self) -> &[u8];
}

impl ChannelTargeted for JoinResult {
    fn get_channel(&self) -> &[u8] {
        match self {
            &Ok(ref join_succ) => join_succ.channel.as_slice(),
            &Err(ref join_err) => join_err.channel.as_slice()
        }
    }
}

#[derive(Clone, Debug)]
pub struct JoinSuccess {
    pub channel: Vec<u8>,
    pub nicks: Vec<String>,
    pub topic: Option<TopicMeta>,
}

#[derive(Clone, Debug)]
pub struct TopicMeta {
    pub text: Vec<u8>,
    pub set_at: u64,
    pub set_by: String,
}

impl TopicMeta {
    fn new(topic: &Vec<u8>, other: &BundlerTopicMeta) -> TopicMeta {
        TopicMeta {
            text: topic.clone(),
            set_at: other.set_at,
            set_by: other.set_by.clone(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct JoinError {
    pub channel: Vec<u8>,
    pub errcode: i16,
    pub message: String
}

pub struct JoinBundlerTrigger {
    current_nick: Vec<u8>,
}

impl JoinBundlerTrigger {
    pub fn new(nick: &[u8]) -> JoinBundlerTrigger {
        JoinBundlerTrigger {
            current_nick: nick.to_vec()
        }
    }

    fn on_nick(&mut self, msg: &IrcMsg) {
        let is_self_nick = msg.get_prefix().nick()
            .and_then(|nick| Some(nick.as_bytes() == self.current_nick.as_slice()))
            .unwrap_or(false);

        if is_self_nick {
            info!("{:?} detected nick change {:?} -> {:?}",
                self, self.current_nick, &msg[0]);
            self.current_nick = msg[0].to_vec();
        }
    }

    fn is_self_join(&self, msg: &IrcMsg) -> bool {
        msg.get_prefix().nick()
            .and_then(|nick| Some(nick.as_bytes() == self.current_nick.as_slice()))
            .unwrap_or(false)
    }
}

impl BundlerTrigger for JoinBundlerTrigger {
    fn on_irc_msg(&mut self, msg: &IrcMsg) -> Vec<Box<Bundler+Send>> {
        match msg.get_command() {
            "JOIN" => {
                let mut out = Vec::new();
                if self.is_self_join(msg) {
                    let channel = &msg[0];
                    let bundler: Box<Bundler+Send> = Box::new(JoinBundler::new(channel));
                    out.push(bundler);
                }
                out
            },
            "NICK" => {
                // potentially our nick is changing
                self.on_nick(msg);
                Vec::new()
            }
            _ => Vec::new()
        }
    }
}

impl fmt::Debug for JoinBundlerTrigger {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundlerTrigger(current_nick={:?})", self.current_nick.as_slice())
    }
}

struct BundlerTopicMeta {
    set_by: String,
    set_at: u64,
}

impl BundlerTopicMeta {
    fn from_msg(msg: &IrcMsg) -> Option<BundlerTopicMeta> {
        let args2 = match ::std::str::from_utf8(&msg[2]) {
            Ok(args3) => args3,
            Err(_) => return None,
        };
        let args3 = match ::std::str::from_utf8(&msg[3]) {
            Ok(args3) => args3,
            Err(_) => return None,
        };
        match args3.parse().ok() {
            Some(set_at) => {
                Some(BundlerTopicMeta {
                    set_by: args2.to_string(),
                    set_at: set_at,
                })
            },
            None => None
        }
    }
}

pub struct JoinBundler {
    channel: Vec<u8>,
    topic: Option<Vec<u8>>,
    topic_meta: Option<BundlerTopicMeta>,
    nicks: Option<Vec<String>>,
    state: JoinBundlerState,
    result: Option<JoinResult>,
}

enum JoinBundlerState {
    PreJoin,
    Joining,
    Joined,
    JoinFail
}

impl JoinBundler {
    pub fn new(channel: &[u8]) -> JoinBundler {
        JoinBundler {
            channel: channel.to_vec(),
            topic: None,
            topic_meta: None,
            nicks: Some(Vec::new()),
            state: JoinBundlerState::PreJoin,
            result: None
        }
    }

    fn accept_state_prejoin(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        let success = match msg.get_command() {
            "JOIN" => {
                if !msg[0].eq_ignore_irc_case(self.channel.as_slice()) {
                    return None;
                }
                true
            },
            "475" => {
                if !msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                    return None;
                }
                false
            },
            _ => return None
        };

        if !success {
            self.result = Some(Err(JoinError {
                channel: self.channel.as_slice().to_vec(),
                errcode: 0,
                message: String::from_str("")
            }));
        }
        Some(if success { JoinBundlerState::Joining } else { JoinBundlerState::JoinFail })
    }

    fn on_topic(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        self.topic = Some(msg[2].to_vec());
        None
    }

    fn on_topic_meta(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        self.topic_meta = BundlerTopicMeta::from_msg(msg);
        None
    }

    fn on_names(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        // FIXME
        let nicks_data = String::from_utf8_lossy(&msg[3]);

        if let Some(nicks) = self.nicks.as_mut() {
            for nick in nicks_data.split(' ') {
                if nick.len() > 0 {
                    nicks.push(nick.to_string());
                }
            }
        }
        None
    }

    fn on_names_end(&mut self, _: &IrcMsg) -> Option<JoinBundlerState> {
        let topic = match (self.topic.as_ref(), self.topic_meta.as_ref()) {
            (Some(topic), Some(topic_meta)) => {
                Some(TopicMeta::new(topic, topic_meta))
            },
            _ => None
        };
        self.result = Some(Ok(JoinSuccess {
            channel: self.channel.clone(),
            nicks: self.nicks.take().unwrap(),
            topic: topic
        }));
        Some(JoinBundlerState::Joined)
    }

    fn accept_state_joining(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        if msg.get_command() == "332" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_topic(msg);
            }
            return None;
        }
        if msg.get_command() == "333" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_topic_meta(msg);
            }
            return None;
        }
        if msg.get_command() == "353" {
            assert!(match &msg[1] {
                b"=" | b"*" | b"@" => true,
                _ => false
            });
            if msg[2].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_names(msg);
            }
            return None;
        }
        if msg.get_command() == "366" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_names_end(msg);
            }
            return None;
        }
        None
    }
}

impl Bundler for JoinBundler {
    fn on_irc_msg(&mut self, msg: &IrcMsg) -> Vec<IrcEvent> {
        let new_state = match self.state {
            JoinBundlerState::PreJoin => self.accept_state_prejoin(msg),
            JoinBundlerState::Joining => self.accept_state_joining(msg),
            _ => None
        };
        match new_state {
            Some(new_state) => {
                self.state = new_state;
            },
            None => ()
        }
        match self.result.take() {
            Some(result) => {
                vec![IrcEvent::JoinBundle(result)]
            },
            None => vec![]
        }
    }

    fn is_finished(&mut self) -> bool {
        match self.state {
            JoinBundlerState::JoinFail | JoinBundlerState::Joined => true,
            _ => false
        }
    }

    fn get_name(&self) -> &'static str {
        "JoinBundler"
    }
}

impl fmt::Debug for JoinBundler {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundler({:?})", self.channel.as_slice())
    }
}<commit_msg>Update deprecated code<commit_after>use std::fmt;
use irccase::IrcAsciiExt;

use parse::IrcMsg;
use watchers::base::{Bundler, BundlerTrigger};
use event::IrcEvent;

pub type JoinResult = Result<JoinSuccess, JoinError>;

trait ChannelTargeted {
    fn get_channel(&self) -> &[u8];
}

impl ChannelTargeted for JoinResult {
    fn get_channel(&self) -> &[u8] {
        match self {
            &Ok(ref join_succ) => join_succ.channel.as_slice(),
            &Err(ref join_err) => join_err.channel.as_slice()
        }
    }
}

#[derive(Clone, Debug)]
pub struct JoinSuccess {
    pub channel: Vec<u8>,
    pub nicks: Vec<String>,
    pub topic: Option<TopicMeta>,
}

#[derive(Clone, Debug)]
pub struct TopicMeta {
    pub text: Vec<u8>,
    pub set_at: u64,
    pub set_by: String,
}

impl TopicMeta {
    fn new(topic: &Vec<u8>, other: &BundlerTopicMeta) -> TopicMeta {
        TopicMeta {
            text: topic.clone(),
            set_at: other.set_at,
            set_by: other.set_by.clone(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct JoinError {
    pub channel: Vec<u8>,
    pub errcode: i16,
    pub message: String
}

pub struct JoinBundlerTrigger {
    current_nick: Vec<u8>,
}

impl JoinBundlerTrigger {
    pub fn new(nick: &[u8]) -> JoinBundlerTrigger {
        JoinBundlerTrigger {
            current_nick: nick.to_vec()
        }
    }

    fn on_nick(&mut self, msg: &IrcMsg) {
        let is_self_nick = msg.get_prefix().nick()
            .and_then(|nick| Some(nick.as_bytes() == self.current_nick.as_slice()))
            .unwrap_or(false);

        if is_self_nick {
            info!("{:?} detected nick change {:?} -> {:?}",
                self, self.current_nick, &msg[0]);
            self.current_nick = msg[0].to_vec();
        }
    }

    fn is_self_join(&self, msg: &IrcMsg) -> bool {
        msg.get_prefix().nick()
            .and_then(|nick| Some(nick.as_bytes() == self.current_nick.as_slice()))
            .unwrap_or(false)
    }
}

impl BundlerTrigger for JoinBundlerTrigger {
    fn on_irc_msg(&mut self, msg: &IrcMsg) -> Vec<Box<Bundler+Send>> {
        match msg.get_command() {
            "JOIN" => {
                let mut out = Vec::new();
                if self.is_self_join(msg) {
                    let channel = &msg[0];
                    let bundler: Box<Bundler+Send> = Box::new(JoinBundler::new(channel));
                    out.push(bundler);
                }
                out
            },
            "NICK" => {
                // potentially our nick is changing
                self.on_nick(msg);
                Vec::new()
            }
            _ => Vec::new()
        }
    }
}

impl fmt::Debug for JoinBundlerTrigger {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundlerTrigger(current_nick={:?})", self.current_nick.as_slice())
    }
}

struct BundlerTopicMeta {
    set_by: String,
    set_at: u64,
}

impl BundlerTopicMeta {
    fn from_msg(msg: &IrcMsg) -> Option<BundlerTopicMeta> {
        let args2 = match ::std::str::from_utf8(&msg[2]) {
            Ok(args3) => args3,
            Err(_) => return None,
        };
        let args3 = match ::std::str::from_utf8(&msg[3]) {
            Ok(args3) => args3,
            Err(_) => return None,
        };
        match args3.parse().ok() {
            Some(set_at) => {
                Some(BundlerTopicMeta {
                    set_by: args2.to_string(),
                    set_at: set_at,
                })
            },
            None => None
        }
    }
}

pub struct JoinBundler {
    channel: Vec<u8>,
    topic: Option<Vec<u8>>,
    topic_meta: Option<BundlerTopicMeta>,
    nicks: Option<Vec<String>>,
    state: JoinBundlerState,
    result: Option<JoinResult>,
}

enum JoinBundlerState {
    PreJoin,
    Joining,
    Joined,
    JoinFail
}

impl JoinBundler {
    pub fn new(channel: &[u8]) -> JoinBundler {
        JoinBundler {
            channel: channel.to_vec(),
            topic: None,
            topic_meta: None,
            nicks: Some(Vec::new()),
            state: JoinBundlerState::PreJoin,
            result: None
        }
    }

    fn accept_state_prejoin(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        let success = match msg.get_command() {
            "JOIN" => {
                if !msg[0].eq_ignore_irc_case(self.channel.as_slice()) {
                    return None;
                }
                true
            },
            "475" => {
                if !msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                    return None;
                }
                false
            },
            _ => return None
        };

        if !success {
            self.result = Some(Err(JoinError {
                channel: self.channel.as_slice().to_vec(),
                errcode: 0,
                message: String::new(),
            }));
        }
        Some(if success { JoinBundlerState::Joining } else { JoinBundlerState::JoinFail })
    }

    fn on_topic(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        self.topic = Some(msg[2].to_vec());
        None
    }

    fn on_topic_meta(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        self.topic_meta = BundlerTopicMeta::from_msg(msg);
        None
    }

    fn on_names(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        // FIXME
        let nicks_data = String::from_utf8_lossy(&msg[3]);

        if let Some(nicks) = self.nicks.as_mut() {
            for nick in nicks_data.split(' ') {
                if nick.len() > 0 {
                    nicks.push(nick.to_string());
                }
            }
        }
        None
    }

    fn on_names_end(&mut self, _: &IrcMsg) -> Option<JoinBundlerState> {
        let topic = match (self.topic.as_ref(), self.topic_meta.as_ref()) {
            (Some(topic), Some(topic_meta)) => {
                Some(TopicMeta::new(topic, topic_meta))
            },
            _ => None
        };
        self.result = Some(Ok(JoinSuccess {
            channel: self.channel.clone(),
            nicks: self.nicks.take().unwrap(),
            topic: topic
        }));
        Some(JoinBundlerState::Joined)
    }

    fn accept_state_joining(&mut self, msg: &IrcMsg) -> Option<JoinBundlerState> {
        if msg.get_command() == "332" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_topic(msg);
            }
            return None;
        }
        if msg.get_command() == "333" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_topic_meta(msg);
            }
            return None;
        }
        if msg.get_command() == "353" {
            assert!(match &msg[1] {
                b"=" | b"*" | b"@" => true,
                _ => false
            });
            if msg[2].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_names(msg);
            }
            return None;
        }
        if msg.get_command() == "366" {
            if msg[1].eq_ignore_irc_case(self.channel.as_slice()) {
                return self.on_names_end(msg);
            }
            return None;
        }
        None
    }
}

impl Bundler for JoinBundler {
    fn on_irc_msg(&mut self, msg: &IrcMsg) -> Vec<IrcEvent> {
        let new_state = match self.state {
            JoinBundlerState::PreJoin => self.accept_state_prejoin(msg),
            JoinBundlerState::Joining => self.accept_state_joining(msg),
            _ => None
        };
        match new_state {
            Some(new_state) => {
                self.state = new_state;
            },
            None => ()
        }
        match self.result.take() {
            Some(result) => {
                vec![IrcEvent::JoinBundle(result)]
            },
            None => vec![]
        }
    }

    fn is_finished(&mut self) -> bool {
        match self.state {
            JoinBundlerState::JoinFail | JoinBundlerState::Joined => true,
            _ => false
        }
    }

    fn get_name(&self) -> &'static str {
        "JoinBundler"
    }
}

impl fmt::Debug for JoinBundler {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "JoinBundler({:?})", self.channel.as_slice())
    }
}<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::str::FromStr;
use std::ascii::AsciiExt;

header! { (Destination, "Destination") => [String] }

header! { (Depth, "Depth") => [String] }
// TODO header! { (Depth, "Depth") => [DepthValue] }

pub enum DepthValue {
    Zero,
    One,
    Infinity,
    Ext(String),
}

impl DepthValue {
    fn name(&self) -> &str {
        match *self {
            DepthValue::Zero => "0",
            DepthValue::One => "1",
            DepthValue::Infinity => "Infinity",
            DepthValue::Ext(ref s) => &s
        }
    }
}

impl Display for DepthValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.name())
    }
}

impl FromStr for DepthValue {
    type Err = ();
    fn from_str(s: &str) -> Result<DepthValue, ()> {
        Ok(match s.to_ascii_uppercase().as_ref() {
            "0" => DepthValue::Zero,
            "1" => DepthValue::One,
            "INFINITY" => DepthValue::Infinity,
            s => DepthValue::Ext(s.to_owned()),
        })
    }
}
<commit_msg>refactor(header): forgot to remove the header stuff<commit_after>use std::fmt::{self, Display};
use std::str::FromStr;
use std::ascii::AsciiExt;

header! { (Destination, "Destination") => [String] }

header! { (Depth, "Depth") => [String] }
// TODO header! { (Depth, "Depth") => [DepthValue] }
<|endoftext|>


<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 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: Stop using Foo name 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 Wrapper {
        pub flows: Vec<LoginType>,
    }

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

    #[test]
    #[cfg(feature = "unstable-pre-spec")]
    fn deserialize_sso_login_type() {
        let mut wrapper = from_json_value::<Wrapper>(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 = wrapper.flows.pop();
        assert_matches!(wrapper.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 wrapper = to_json_value(Wrapper {
            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!(
            wrapper,
            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>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::collections::HashSet;
use std::ffi::OsStr;
use std::process::{Command, ExitStatus, Output};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));

struct Result {
    stdout: String,
    stderr: String,
    status: ExitStatus,
}

impl From<Output> for Result {
    fn from(output: Output) -> Result {
        Result {
            status: output.status,
            stdout: String::from_utf8(output.stdout).expect("Failed to decode stdout"),
            stderr: String::from_utf8(output.stderr).expect("Failed to decode stderr"),
        }
    }
}

fn run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    Command::new("cargo")
        .arg("run")
        .arg("--quiet")
        .arg("--")
        .args(args)
        .output()
        .expect("Failed to run xkpwgen for testing")
        .into()
}

fn assert_run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    let result = run(args);
    assert!(result.status.success(),
            "xkpwgen failed with output:
stdout:
{}
stderr:
{}
",
            result.stdout,
            result.stderr);
    result
}

fn all_words<'a>(s: &'a str, sep: &str) -> Vec<&'a str> {
    s.lines().flat_map(|w| w.split(sep)).collect()
}

macro_rules! repeat_run {
    ($result:ident, $command:expr, $body:block) => {
        {
            for _ in 0..10 {
                let $result = assert_run($command);
                $body;
            }
        }
    };

    ($result:ident, $body:block) => {
        {
        let command: Vec<String> = Vec::new();
        repeat_run!($result, &command, $body);
        }
    };
}

#[test]
fn it_includes_license_and_warranty_in_help() {
    let result = assert_run(&["--help"]);
    assert!(result.stdout.contains("GNU GPL version 3 or later"),
            "License name missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("<http://gnu.org/licenses/gpl.html>"),
            "License URL missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("There is NO WARRANTY, to the extent permitted by law."),
            "Warranty disclaimer missing in output:
{}",
            result.stdout);
}

#[test]
fn it_uses_only_words_from_the_wordlist() {
    let words = EFF_WORDLIST.lines().collect::<HashSet<_>>();
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(words.contains(word), "Word {} not in EFF wordlist!", word);
        }
    });
}

#[test]
fn it_generates_five_phrases_by_default() {
    repeat_run!(result, {
        assert_eq!(result.stdout.lines().count(), 5);
    })
}

#[test]
fn it_generates_the_given_number_of_passwords() {
    repeat_run!(result, &["-n", "10"], {
        assert_eq!(result.stdout.lines().count(), 10);
    })
}

#[test]
fn it_generates_four_words_per_password_by_default() {
    repeat_run!(result, {
        for password in result.stdout.lines() {
            assert_eq!(all_words(password, " ").len(), 4);
        }
    })
}

#[test]
fn it_generates_the_given_number_of_words_per_password() {
    repeat_run!(result, &["-l", "9"], {
        for password in result.stdout.lines() {
            assert_eq!(all_words(password, " ").len(), 9)
        }
    });
}

#[test]
fn it_generates_no_words_with_whitespace() {
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(!word.contains(|c: char| c.is_whitespace()),
                    "Word {} contained whitespace!",
                    word);
        }
    })
}

#[test]
fn it_generates_no_empty_words() {
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(word.len() > 0, "Got empty word");
        }
    })
}

#[test]
fn it_has_7776_words_in_the_wordlist() {
    let stdout = assert_run(&["--words"]).stdout;
    assert_eq!(stdout.lines().count(), 7776);
}

#[test]
fn it_has_no_duplicate_words_in_the_wordlist() {
    let mut seen_words = HashSet::with_capacity(8000);
    let mut duplicate_words = HashSet::new();
    for word in EFF_WORDLIST.lines() {
        if !seen_words.insert(word) {
            duplicate_words.insert(word);
        }
    }

    assert!(duplicate_words.is_empty(),
            "Duplicate words found: {}",
            duplicate_words.into_iter().collect::<Vec<_>>().join(" "));
}

#[test]
fn it_has_no_empty_word_in_the_wordlist() {
    let stdout = assert_run(&["--words"]).stdout;
    for word in stdout.lines() {
        assert!(word.len() > 0, "Got empty word");
    }
}

#[test]
fn it_has_no_word_with_space_in_the_wordlist() {
    let stdout = assert_run(&["--words"]).stdout;
    for word in stdout.lines() {
        assert!(!word.contains(|c: char| c.is_whitespace()),
                "Word {} contained whitespace!",
                word);
    }
}

#[test]
fn it_uses_the_original_eff_wordlist() {
    let stdout = assert_run(&["--words"]).stdout;
    assert_eq!(stdout.lines().collect::<Vec<_>>(),
               EFF_WORDLIST.lines().collect::<Vec<_>>());
}
<commit_msg>Test against the embedded wordlist<commit_after>/*
 * Copyright (C) 2017  Sebastian Wiesner <swiesner@lunaryorn.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

use std::collections::HashSet;
use std::ffi::OsStr;
use std::process::{Command, ExitStatus, Output};

static EFF_WORDLIST: &'static str = include_str!(concat!(env!("OUT_DIR"), "/eff_wordlist.txt"));

struct Result {
    stdout: String,
    stderr: String,
    status: ExitStatus,
}

impl From<Output> for Result {
    fn from(output: Output) -> Result {
        Result {
            status: output.status,
            stdout: String::from_utf8(output.stdout).expect("Failed to decode stdout"),
            stderr: String::from_utf8(output.stderr).expect("Failed to decode stderr"),
        }
    }
}

fn run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    Command::new("cargo")
        .arg("run")
        .arg("--quiet")
        .arg("--")
        .args(args)
        .output()
        .expect("Failed to run xkpwgen for testing")
        .into()
}

fn assert_run<S: AsRef<OsStr>>(args: &[S]) -> Result {
    let result = run(args);
    assert!(result.status.success(),
            "xkpwgen failed with output:
stdout:
{}
stderr:
{}
",
            result.stdout,
            result.stderr);
    result
}

fn all_words<'a>(s: &'a str, sep: &str) -> Vec<&'a str> {
    s.lines().flat_map(|w| w.split(sep)).collect()
}

macro_rules! repeat_run {
    ($result:ident, $command:expr, $body:block) => {
        {
            for _ in 0..10 {
                let $result = assert_run($command);
                $body;
            }
        }
    };

    ($result:ident, $body:block) => {
        {
        let command: Vec<String> = Vec::new();
        repeat_run!($result, &command, $body);
        }
    };
}

#[test]
fn it_includes_license_and_warranty_in_help() {
    let result = assert_run(&["--help"]);
    assert!(result.stdout.contains("GNU GPL version 3 or later"),
            "License name missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("<http://gnu.org/licenses/gpl.html>"),
            "License URL missing in output:
{}",
            result.stdout);
    assert!(result.stdout.contains("There is NO WARRANTY, to the extent permitted by law."),
            "Warranty disclaimer missing in output:
{}",
            result.stdout);
}

#[test]
fn it_uses_only_words_from_the_wordlist() {
    let words = EFF_WORDLIST.lines().collect::<HashSet<_>>();
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(words.contains(word), "Word {} not in EFF wordlist!", word);
        }
    });
}

#[test]
fn it_generates_five_phrases_by_default() {
    repeat_run!(result, {
        assert_eq!(result.stdout.lines().count(), 5);
    })
}

#[test]
fn it_generates_the_given_number_of_passwords() {
    repeat_run!(result, &["-n", "10"], {
        assert_eq!(result.stdout.lines().count(), 10);
    })
}

#[test]
fn it_generates_four_words_per_password_by_default() {
    repeat_run!(result, {
        for password in result.stdout.lines() {
            assert_eq!(all_words(password, " ").len(), 4);
        }
    })
}

#[test]
fn it_generates_the_given_number_of_words_per_password() {
    repeat_run!(result, &["-l", "9"], {
        for password in result.stdout.lines() {
            assert_eq!(all_words(password, " ").len(), 9)
        }
    });
}

#[test]
fn it_generates_no_words_with_whitespace() {
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(!word.contains(|c: char| c.is_whitespace()),
                    "Word {} contained whitespace!",
                    word);
        }
    })
}

#[test]
fn it_generates_no_empty_words() {
    repeat_run!(result, {
        for word in all_words(&result.stdout, " ") {
            assert!(word.len() > 0, "Got empty word");
        }
    })
}

#[test]
fn it_uses_the_original_eff_wordlist() {
    let stdout = assert_run(&["--words"]).stdout;
    assert_eq!(stdout.lines().collect::<Vec<_>>(),
               EFF_WORDLIST.lines().collect::<Vec<_>>());
}

#[test]
fn it_has_7776_words_in_the_wordlist() {
    assert_eq!(EFF_WORDLIST.lines().count(), 7776);
}

#[test]
fn it_has_no_duplicate_words_in_the_wordlist() {
    let mut seen_words = HashSet::with_capacity(8000);
    let mut duplicate_words = HashSet::new();
    for word in EFF_WORDLIST.lines() {
        if !seen_words.insert(word) {
            duplicate_words.insert(word);
        }
    }

    assert!(duplicate_words.is_empty(),
            "Duplicate words found: {}",
            duplicate_words.into_iter().collect::<Vec<_>>().join(" "));
}

#[test]
fn it_has_no_empty_word_in_the_wordlist() {
    for word in EFF_WORDLIST.lines() {
        assert!(word.len() > 0, "Got empty word");
    }
}

#[test]
fn it_has_no_word_with_space_in_the_wordlist() {
    for word in EFF_WORDLIST.lines() {
        assert!(!word.contains(|c: char| c.is_whitespace()),
                "Word {} contained whitespace!",
                word);
    }
}
<|endoftext|>


<commit_before>use std::process::Command;

#[test]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    // Skip this test if rustup nightly is unavailable
    let rustup_output = Command::new("rustup")
        .args(&["component", "list", "--toolchain", "nightly"])
        .output()
        .unwrap();
    assert!(rustup_output.status.success());
    let component_output = String::from_utf8_lossy(&rustup_output.stdout);
    if !component_output.contains("rustfmt") {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let output = Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["+nightly", "run", "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(
        output.status.success(),
        "Formatting check failed. Run `./util/dev fmt` to update formatting."
    );
}
<commit_msg>build(tests/fmt): use shared target dir<commit_after>use std::process::Command;

#[test]
fn fmt() {
    if option_env!("RUSTC_TEST_SUITE").is_some() {
        return;
    }

    // Skip this test if rustup nightly is unavailable
    let rustup_output = Command::new("rustup")
        .args(&["component", "list", "--toolchain", "nightly"])
        .output()
        .unwrap();
    assert!(rustup_output.status.success());
    let component_output = String::from_utf8_lossy(&rustup_output.stdout);
    if !component_output.contains("rustfmt") {
        return;
    }

    let root_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let dev_dir = root_dir.join("clippy_dev");
    let target_dir = root_dir.join("target");
    let target_dir = target_dir.to_str().unwrap();
    let output = Command::new("cargo")
        .current_dir(dev_dir)
        .args(&["+nightly", "run", "--target-dir", target_dir, "--", "fmt", "--check"])
        .output()
        .unwrap();

    println!("status: {}", output.status);
    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(
        output.status.success(),
        "Formatting check failed. Run `./util/dev fmt` to update formatting."
    );
}
<|endoftext|>


<commit_before>
extern crate rand;
extern crate ndarray;
extern crate ndarray_rand;
extern crate ndarray_linalg as linalg;

use ndarray::prelude::*;
use linalg::SquareMatrix;
use rand::distributions::*;
use ndarray_rand::RandomExt;

fn all_close(a: Array<f64, (Ix, Ix)>, b: Array<f64, (Ix, Ix)>) {
    if !a.all_close(&b, 1.0e-7) {
        panic!("\nTwo matrices are not equal:\na = \n{:?}\nb = \n{:?}\n",
               a,
               b);
    }
}

#[test]
fn inv_random() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random((3, 3), r_dist);
    let ai = a.clone().inv().unwrap();
    let id = Array::eye(3);
    all_close(ai.dot(&a), id);
}

#[test]
#[should_panic]
fn inv_error() {
    // do not have inverse
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap();
    let _ = a.clone().inv().unwrap();
}
<commit_msg>Add test for inv (not passed)<commit_after>
extern crate rand;
extern crate ndarray;
extern crate ndarray_rand;
extern crate ndarray_linalg as linalg;

use ndarray::prelude::*;
use linalg::SquareMatrix;
use rand::distributions::*;
use ndarray_rand::RandomExt;

fn all_close(a: Array<f64, (Ix, Ix)>, b: Array<f64, (Ix, Ix)>) {
    if !a.all_close(&b, 1.0e-7) {
        panic!("\nTwo matrices are not equal:\na = \n{:?}\nb = \n{:?}\n",
               a,
               b);
    }
}

#[test]
fn inv_random() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random((3, 3), r_dist);
    let ai = a.clone().inv().unwrap();
    let id = Array::eye(3);
    all_close(ai.dot(&a), id);
}

#[test]
fn inv_random_t() {
    let r_dist = Range::new(0., 1.);
    let a = Array::<f64, _>::random((3, 3), r_dist).reversed_axes();
    let ai = a.clone().inv().unwrap();
    let id = Array::eye(3);
    all_close(ai.dot(&a), id);
}

#[test]
#[should_panic]
fn inv_error() {
    // do not have inverse
    let a = Array::range(1., 10., 1.).into_shape((3, 3)).unwrap();
    let _ = a.clone().inv().unwrap();
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;

#[derive(Debug)]
pub struct NiceOutput {
    pub status: i32,
    pub stdout: String,
    pub stderr: String,
}

fn run(args: Vec<&str>) -> NiceOutput {
    let mut directory = env::current_exe().unwrap();
            directory.pop(); // chop off exe name but leave "debug"
    let name = format!("to{}", env::consts::EXE_SUFFIX);
    let binary = directory.join(&name);

    let mut command = Command::new(binary);
            command.args(&args);
    let output = command.output().unwrap();
    let stdout = trim(output.stdout);
    let stderr = trim(output.stderr);

    return NiceOutput {
        status: output.status.code().unwrap(),
        stdout: stdout,
        stderr: stderr,
    };
}

fn trim(output: Vec<u8>) -> String {
    let string = String::from_utf8(output).unwrap();
    return String::from(string.trim());
}

#[test]
fn smoke_test() {
    let result = run(vec!["-h"]);
    assert_eq!(result.status, 0);
}

#[test]
fn version_test() {
    let result = run(vec!["--version"]);
    let version = env!("CARGO_PKG_VERSION");
    let expected = format!("to {}", version);

    assert_eq!(result.stdout, expected);
}
<commit_msg>Adds test for short version flag.<commit_after>use std::env;
use std::process::Command;

#[derive(Debug)]
pub struct NiceOutput {
    pub status: i32,
    pub stdout: String,
    pub stderr: String,
}

fn run(args: Vec<&str>) -> NiceOutput {
    let mut directory = env::current_exe().unwrap();
            directory.pop(); // chop off exe name but leave "debug"
    let name = format!("to{}", env::consts::EXE_SUFFIX);
    let binary = directory.join(&name);

    let mut command = Command::new(binary);
            command.args(&args);
    let output = command.output().unwrap();
    let stdout = trim(output.stdout);
    let stderr = trim(output.stderr);

    return NiceOutput {
        status: output.status.code().unwrap(),
        stdout: stdout,
        stderr: stderr,
    };
}

fn trim(output: Vec<u8>) -> String {
    let string = String::from_utf8(output).unwrap();
    return String::from(string.trim());
}

#[test]
fn smoke_test() {
    let result = run(vec!["-h"]);
    assert_eq!(result.status, 0);
}

#[test]
fn version_test_long() {
    let result = run(vec!["--version"]);
    let version = env!("CARGO_PKG_VERSION");
    let expected = format!("to {}", version);

    assert_eq!(result.stdout, expected);
}

#[test]
fn version_test_short() {
    let result = run(vec!["-V"]);
    let version = env!("CARGO_PKG_VERSION");
    let expected = format!("to {}", version);

    assert_eq!(result.stdout, expected);
}
<|endoftext|>