<commit_before>//! This modules contains [Cassandra's errors]
//! (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011)
//! which server could respond to client.

use std::io;
use std::result;

use error;
use consistency::Consistency;
use types::*;
use FromCursor;
use frame::Frame;

/// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
///
/// [`Frame`]: ../frame/struct.Frame.html
pub type Result = result::Result<Frame, CDRSError>;

/// CDRS error which could be returned by Cassandra server as a response. As it goes
/// from the specification it contains an error code and an error message. Apart of those
/// depending of type of error it could contain an additional information about an error.
/// This additional information is represented by `additional_info` property which is `ErrorKind`.
#[derive(Debug)]
pub struct CDRSError {
    /// `i32` that points to a type of error.
    pub error_code: CInt,
    /// Error message string.
    pub message: CString,
    /// Additional information.
    pub additional_info: AdditionalErrorInfo,
}

impl FromCursor for CDRSError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<CDRSError> {
        let error_code = CInt::from_cursor(&mut cursor)?;
        let message = CString::from_cursor(&mut cursor)?;
        let additional_info = AdditionalErrorInfo::from_cursor_with_code(&mut cursor, error_code)?;

        Ok(CDRSError {
               error_code: error_code,
               message: message,
               additional_info: additional_info,
           })
    }
}

/// Additional error info in accordance to
/// [Cassandra protocol v4]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011).
#[derive(Debug)]
pub enum AdditionalErrorInfo {
    Server(SimpleError),
    Protocol(SimpleError),
    Authentication(SimpleError),
    Unavailable(UnavailableError),
    Overloaded(SimpleError),
    IsBootstrapping(SimpleError),
    Truncate(SimpleError),
    WriteTimeout(WriteTimeoutError),
    ReadTimeout(ReadTimeoutError),
    ReadFailure(ReadFailureError),
    FunctionFailure(FunctionFailureError),
    WriteFailure(WriteFailureError),
    Syntax(SimpleError),
    Unauthorized(SimpleError),
    Invalid(SimpleError),
    Config(SimpleError),
    AlreadyExists(AlreadyExistsError),
    Unprepared(UnpreparedError),
}

impl AdditionalErrorInfo {
    pub fn from_cursor_with_code(mut cursor: &mut io::Cursor<&[u8]>,
                                 error_code: CInt)
                                 -> error::Result<AdditionalErrorInfo> {
        match error_code {
            0x0000 => Ok(AdditionalErrorInfo::Server(SimpleError::from_cursor(&mut cursor)?)),
            0x000A => Ok(AdditionalErrorInfo::Protocol(SimpleError::from_cursor(&mut cursor)?)),
            0x0100 => {
                Ok(AdditionalErrorInfo::Authentication(SimpleError::from_cursor(&mut cursor)?))
            }
            0x1000 => {
                Ok(AdditionalErrorInfo::Unavailable(UnavailableError::from_cursor(&mut cursor)?))
            }
            0x1001 => Ok(AdditionalErrorInfo::Overloaded(SimpleError::from_cursor(&mut cursor)?)),
            0x1002 => {
                Ok(AdditionalErrorInfo::IsBootstrapping(SimpleError::from_cursor(&mut cursor)?))
            }
            0x1003 => Ok(AdditionalErrorInfo::Truncate(SimpleError::from_cursor(&mut cursor)?)),
            0x1100 => {
                Ok(AdditionalErrorInfo::WriteTimeout(WriteTimeoutError::from_cursor(&mut cursor)?))
            }
            0x1200 => {
                Ok(AdditionalErrorInfo::ReadTimeout(ReadTimeoutError::from_cursor(&mut cursor)?))
            }
            0x1300 => {
                Ok(AdditionalErrorInfo::ReadFailure(ReadFailureError::from_cursor(&mut cursor)?))
            }
            0x1400 => {
                   Ok(AdditionalErrorInfo::FunctionFailure(
                       FunctionFailureError::from_cursor(&mut cursor)?))
               }
            0x1500 => {
                Ok(AdditionalErrorInfo::WriteFailure(WriteFailureError::from_cursor(&mut cursor)?))
            }
            0x2000 => Ok(AdditionalErrorInfo::Syntax(SimpleError::from_cursor(&mut cursor)?)),
            0x2100 => Ok(AdditionalErrorInfo::Unauthorized(SimpleError::from_cursor(&mut cursor)?)),
            0x2200 => Ok(AdditionalErrorInfo::Invalid(SimpleError::from_cursor(&mut cursor)?)),
            0x2300 => Ok(AdditionalErrorInfo::Config(SimpleError::from_cursor(&mut cursor)?)),
            0x2400 => {
                   Ok(AdditionalErrorInfo::AlreadyExists(AlreadyExistsError::from_cursor(&mut cursor)?))
               }
            0x2500 => {
                Ok(AdditionalErrorInfo::Unprepared(UnpreparedError::from_cursor(&mut cursor)?))
            }
            _ => Err("Unexpected additional error info".into()),
        }
    }
}

/// Is used if error does not contain any additional info.
#[derive(Debug)]
pub struct SimpleError {}

impl FromCursor for SimpleError {
    fn from_cursor(mut _cursor: &mut io::Cursor<&[u8]>) -> error::Result<SimpleError> {
        Ok(SimpleError {})
    }
}

/// Additional info about
/// [unavailable exception]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1025)
#[derive(Debug)]
pub struct UnavailableError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// Number of nodes that should be available to respect `cl`.
    pub required: CInt,
    /// Number of replicas that we were know to be alive.
    pub alive: CInt,
}

impl FromCursor for UnavailableError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnavailableError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let required = CInt::from_cursor(&mut cursor)?;
        let alive = CInt::from_cursor(&mut cursor)?;

        Ok(UnavailableError {
               cl: cl,
               required: required,
               alive: alive,
           })
    }
}

/// Timeout exception during a write request.
#[derive(Debug)]
pub struct WriteTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Describes the type of the write that timed out
    pub write_type: WriteType,
}

impl FromCursor for WriteTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               write_type: write_type,
           })
    }
}

/// Timeout exception during a read request.
#[derive(Debug)]
pub struct ReadTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    data_present: u8,
}

impl ReadTimeoutError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               data_present: data_present,
           })
    }
}

/// A non-timeout exception during a read request.
#[derive(Debug)]
pub struct ReadFailureError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    data_present: u8,
}

impl ReadFailureError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               data_present: data_present,
           })
    }
}

/// A (user defined) function failed during execution.
#[derive(Debug)]
pub struct FunctionFailureError {
    /// The keyspace of the failed function.
    pub keyspace: CString,
    /// The name of the failed function
    pub function: CString,
    /// `Vec<CString>` one string for each argument type (as CQL type) of the failed function.
    pub arg_types: CStringList,
}

impl FromCursor for FunctionFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<FunctionFailureError> {
        let keyspace = CString::from_cursor(&mut cursor)?;
        let function = CString::from_cursor(&mut cursor)?;
        let arg_types = CStringList::from_cursor(&mut cursor)?;

        Ok(FunctionFailureError {
               keyspace: keyspace,
               function: function,
               arg_types: arg_types,
           })
    }
}

/// A non-timeout exception during a write request.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1106)
#[derive(Debug)]
pub struct WriteFailureError {
    /// Consistency of the query having triggered the exception.
    pub cl: Consistency,
    /// Represents the number of nodes having answered the request.
    pub received: CInt,
    /// Represents the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    /// describes the type of the write that failed.
    pub write_type: WriteType,
}

impl FromCursor for WriteFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               write_type: write_type,
           })
    }
}

/// Describes the type of the write that failed.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1118)
#[derive(Debug)]
pub enum WriteType {
    /// The write was a non-batched non-counter write
    Simple,
    /// The write was a (logged) batch write.
    /// If this type is received, it means the batch log
    /// has been successfully written
    Batch,
    /// The write was an unlogged batch. No batch log write has been attempted.
    UnloggedBatch,
    /// The write was a counter write (batched or not)
    Counter,
    /// The failure occured during the write to the batch log when a (logged) batch
    /// write was requested.
    BatchLog,
}

impl FromCursor for WriteType {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteType> {
        CString::from_cursor(&mut cursor).and_then(|wt| match wt.as_str() {
                                                       "SIMPLE" => Ok(WriteType::Simple),
                                                       "BATCH" => Ok(WriteType::Batch),
                                                       "UNLOGGED_BATCH" => {
                                                           Ok(WriteType::UnloggedBatch)
                                                       }
                                                       "COUNTER" => Ok(WriteType::Counter),
                                                       "BATCH_LOG" => Ok(WriteType::BatchLog),
                                                       _ => Err("Unexpected write type".into()),
                                                   })
    }
}

/// The query attempted to create a keyspace or a table that was already existing.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1140)
#[derive(Debug)]
pub struct AlreadyExistsError {
    /// Represents either the keyspace that already exists,
    /// or the keyspace in which the table that already exists is.
    pub ks: CString,
    /// Represents the name of the table that already exists.
    pub table: CString,
}

impl FromCursor for AlreadyExistsError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<AlreadyExistsError> {
        let ks = CString::from_cursor(&mut cursor)?;
        let table = CString::from_cursor(&mut cursor)?;

        Ok(AlreadyExistsError {
               ks: ks,
               table: table,
           })
    }
}

/// Can be thrown while a prepared statement tries to be
/// executed if the provided prepared statement ID is not known by
/// this host. [Read more...]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1150)
#[derive(Debug)]
pub struct UnpreparedError {
    /// Unknown ID.
    pub id: CBytes,
}

impl FromCursor for UnpreparedError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnpreparedError> {
        let id = CBytes::from_cursor(&mut cursor)?;

        Ok(UnpreparedError { id: id })
    }
}
<commit_msg>Fix clippy warnings<commit_after>//! This modules contains [Cassandra's errors]
//! (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011)
//! which server could respond to client.

use std::io;
use std::result;

use error;
use consistency::Consistency;
use types::*;
use FromCursor;
use frame::Frame;

/// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
///
/// [`Frame`]: ../frame/struct.Frame.html
pub type Result = result::Result<Frame, CDRSError>;

/// CDRS error which could be returned by Cassandra server as a response. As it goes
/// from the specification it contains an error code and an error message. Apart of those
/// depending of type of error it could contain an additional information about an error.
/// This additional information is represented by `additional_info` property which is `ErrorKind`.
#[derive(Debug)]
pub struct CDRSError {
    /// `i32` that points to a type of error.
    pub error_code: CInt,
    /// Error message string.
    pub message: CString,
    /// Additional information.
    pub additional_info: AdditionalErrorInfo,
}

impl FromCursor for CDRSError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<CDRSError> {
        let error_code = CInt::from_cursor(&mut cursor)?;
        let message = CString::from_cursor(&mut cursor)?;
        let additional_info = AdditionalErrorInfo::from_cursor_with_code(&mut cursor, error_code)?;

        Ok(CDRSError {
               error_code: error_code,
               message: message,
               additional_info: additional_info,
           })
    }
}

/// Additional error info in accordance to
/// [Cassandra protocol v4]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011).
#[derive(Debug)]
pub enum AdditionalErrorInfo {
    Server(SimpleError),
    Protocol(SimpleError),
    Authentication(SimpleError),
    Unavailable(UnavailableError),
    Overloaded(SimpleError),
    IsBootstrapping(SimpleError),
    Truncate(SimpleError),
    WriteTimeout(WriteTimeoutError),
    ReadTimeout(ReadTimeoutError),
    ReadFailure(ReadFailureError),
    FunctionFailure(FunctionFailureError),
    WriteFailure(WriteFailureError),
    Syntax(SimpleError),
    Unauthorized(SimpleError),
    Invalid(SimpleError),
    Config(SimpleError),
    AlreadyExists(AlreadyExistsError),
    Unprepared(UnpreparedError),
}

impl AdditionalErrorInfo {
    pub fn from_cursor_with_code(mut cursor: &mut io::Cursor<&[u8]>,
                                 error_code: CInt)
                                 -> error::Result<AdditionalErrorInfo> {
        match error_code {
            0x0000 => Ok(AdditionalErrorInfo::Server(SimpleError::from_cursor(&mut cursor)?)),
            0x000A => Ok(AdditionalErrorInfo::Protocol(SimpleError::from_cursor(&mut cursor)?)),
            0x0100 => {
                Ok(AdditionalErrorInfo::Authentication(SimpleError::from_cursor(&mut cursor)?))
            }
            0x1000 => {
                Ok(AdditionalErrorInfo::Unavailable(UnavailableError::from_cursor(&mut cursor)?))
            }
            0x1001 => Ok(AdditionalErrorInfo::Overloaded(SimpleError::from_cursor(&mut cursor)?)),
            0x1002 => {
                Ok(AdditionalErrorInfo::IsBootstrapping(SimpleError::from_cursor(&mut cursor)?))
            }
            0x1003 => Ok(AdditionalErrorInfo::Truncate(SimpleError::from_cursor(&mut cursor)?)),
            0x1100 => {
                Ok(AdditionalErrorInfo::WriteTimeout(WriteTimeoutError::from_cursor(&mut cursor)?))
            }
            0x1200 => {
                Ok(AdditionalErrorInfo::ReadTimeout(ReadTimeoutError::from_cursor(&mut cursor)?))
            }
            0x1300 => {
                Ok(AdditionalErrorInfo::ReadFailure(ReadFailureError::from_cursor(&mut cursor)?))
            }
            0x1400 => {
                   Ok(AdditionalErrorInfo::FunctionFailure(
                       FunctionFailureError::from_cursor(&mut cursor)?))
               }
            0x1500 => {
                Ok(AdditionalErrorInfo::WriteFailure(WriteFailureError::from_cursor(&mut cursor)?))
            }
            0x2000 => Ok(AdditionalErrorInfo::Syntax(SimpleError::from_cursor(&mut cursor)?)),
            0x2100 => Ok(AdditionalErrorInfo::Unauthorized(SimpleError::from_cursor(&mut cursor)?)),
            0x2200 => Ok(AdditionalErrorInfo::Invalid(SimpleError::from_cursor(&mut cursor)?)),
            0x2300 => Ok(AdditionalErrorInfo::Config(SimpleError::from_cursor(&mut cursor)?)),
            0x2400 => {
                   Ok(AdditionalErrorInfo::AlreadyExists(
                       AlreadyExistsError::from_cursor(&mut cursor)?))
               }
            0x2500 => {
                Ok(AdditionalErrorInfo::Unprepared(UnpreparedError::from_cursor(&mut cursor)?))
            }
            _ => Err("Unexpected additional error info".into()),
        }
    }
}

/// Is used if error does not contain any additional info.
#[derive(Debug)]
pub struct SimpleError {}

impl FromCursor for SimpleError {
    fn from_cursor(mut _cursor: &mut io::Cursor<&[u8]>) -> error::Result<SimpleError> {
        Ok(SimpleError {})
    }
}

/// Additional info about
/// [unavailable exception]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1025)
#[derive(Debug)]
pub struct UnavailableError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// Number of nodes that should be available to respect `cl`.
    pub required: CInt,
    /// Number of replicas that we were know to be alive.
    pub alive: CInt,
}

impl FromCursor for UnavailableError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnavailableError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let required = CInt::from_cursor(&mut cursor)?;
        let alive = CInt::from_cursor(&mut cursor)?;

        Ok(UnavailableError {
               cl: cl,
               required: required,
               alive: alive,
           })
    }
}

/// Timeout exception during a write request.
#[derive(Debug)]
pub struct WriteTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Describes the type of the write that timed out
    pub write_type: WriteType,
}

impl FromCursor for WriteTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               write_type: write_type,
           })
    }
}

/// Timeout exception during a read request.
#[derive(Debug)]
pub struct ReadTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    data_present: u8,
}

impl ReadTimeoutError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               data_present: data_present,
           })
    }
}

/// A non-timeout exception during a read request.
#[derive(Debug)]
pub struct ReadFailureError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    data_present: u8,
}

impl ReadFailureError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               data_present: data_present,
           })
    }
}

/// A (user defined) function failed during execution.
#[derive(Debug)]
pub struct FunctionFailureError {
    /// The keyspace of the failed function.
    pub keyspace: CString,
    /// The name of the failed function
    pub function: CString,
    /// `Vec<CString>` one string for each argument type (as CQL type) of the failed function.
    pub arg_types: CStringList,
}

impl FromCursor for FunctionFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<FunctionFailureError> {
        let keyspace = CString::from_cursor(&mut cursor)?;
        let function = CString::from_cursor(&mut cursor)?;
        let arg_types = CStringList::from_cursor(&mut cursor)?;

        Ok(FunctionFailureError {
               keyspace: keyspace,
               function: function,
               arg_types: arg_types,
           })
    }
}

/// A non-timeout exception during a write request.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1106)
#[derive(Debug)]
pub struct WriteFailureError {
    /// Consistency of the query having triggered the exception.
    pub cl: Consistency,
    /// Represents the number of nodes having answered the request.
    pub received: CInt,
    /// Represents the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    /// describes the type of the write that failed.
    pub write_type: WriteType,
}

impl FromCursor for WriteFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               write_type: write_type,
           })
    }
}

/// Describes the type of the write that failed.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1118)
#[derive(Debug)]
pub enum WriteType {
    /// The write was a non-batched non-counter write
    Simple,
    /// The write was a (logged) batch write.
    /// If this type is received, it means the batch log
    /// has been successfully written
    Batch,
    /// The write was an unlogged batch. No batch log write has been attempted.
    UnloggedBatch,
    /// The write was a counter write (batched or not)
    Counter,
    /// The failure occured during the write to the batch log when a (logged) batch
    /// write was requested.
    BatchLog,
}

impl FromCursor for WriteType {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteType> {
        CString::from_cursor(&mut cursor).and_then(|wt| match wt.as_str() {
                                                       "SIMPLE" => Ok(WriteType::Simple),
                                                       "BATCH" => Ok(WriteType::Batch),
                                                       "UNLOGGED_BATCH" => {
                                                           Ok(WriteType::UnloggedBatch)
                                                       }
                                                       "COUNTER" => Ok(WriteType::Counter),
                                                       "BATCH_LOG" => Ok(WriteType::BatchLog),
                                                       _ => Err("Unexpected write type".into()),
                                                   })
    }
}

/// The query attempted to create a keyspace or a table that was already existing.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1140)
#[derive(Debug)]
pub struct AlreadyExistsError {
    /// Represents either the keyspace that already exists,
    /// or the keyspace in which the table that already exists is.
    pub ks: CString,
    /// Represents the name of the table that already exists.
    pub table: CString,
}

impl FromCursor for AlreadyExistsError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<AlreadyExistsError> {
        let ks = CString::from_cursor(&mut cursor)?;
        let table = CString::from_cursor(&mut cursor)?;

        Ok(AlreadyExistsError {
               ks: ks,
               table: table,
           })
    }
}

/// Can be thrown while a prepared statement tries to be
/// executed if the provided prepared statement ID is not known by
/// this host. [Read more...]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1150)
#[derive(Debug)]
pub struct UnpreparedError {
    /// Unknown ID.
    pub id: CBytes,
}

impl FromCursor for UnpreparedError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnpreparedError> {
        let id = CBytes::from_cursor(&mut cursor)?;

        Ok(UnpreparedError { id: id })
    }
}
<|endoftext|>


<commit_before>/// Checks whether a point is inside a triangle or not
///
/// ```text
/// →   →    →    →   →    →    →   →    →
/// a = AB × AP;  b = BC × BP;  c = CA × CP
///
/// The point is inside iff:
///     sign(a[2]) == sign(b[2]) == sign(c[2])
///
/// A,                      A, -------P   OUTSIDE
/// |\',                    | ',     / |
/// | \ ',                  |   ',  /    .
/// |  \  ',                |     ',      .
/// |   \   ',              |     / ',     .
/// |    P.   ',            |    /    ',    |
/// |   /  '.   ',          |   /       ',   .
/// |  /     `-.  ',        |  /          ',  |
/// | /  INSIDE `-. ',      | /             ', .
/// |/             `-.',    |/                ',|
/// C-------------------B   C-------------------B
/// ```
///
/// **Note:** This function returns true if the point is
/// on any boundary or coincides with any vertex
pub fn is_point_inside_triangle(xa: &[f64], xb: &[f64], xc: &[f64], xp: &[f64]) -> bool {
    if (xp[0] == xa[0] && xp[1] == xa[1]) || (xp[0] == xb[0] && xp[1] == xb[1]) || (xp[0] == xc[0] && xp[1] == xc[1]) {
        return true;
    }
    let na = cross_is_negative(xb[0] - xa[0], xb[1] - xa[1], xp[0] - xa[0], xp[1] - xa[1]);
    let nb = cross_is_negative(xc[0] - xb[0], xc[1] - xb[1], xp[0] - xb[0], xp[1] - xb[1]);
    let nc = cross_is_negative(xa[0] - xc[0], xa[1] - xc[1], xp[0] - xc[0], xp[1] - xc[1]);
    (na && nb && nc) || (!na && !nb && !nc)
}

/// Returns true if the sign of the cross product vector is negative, including -0.0
///
/// Specifically, returns true if the sign of the component of the out-of-plane vector,
/// resulting from the cross product between u and v is negative
#[inline]
fn cross_is_negative(u0: f64, u1: f64, v0: f64, v1: f64) -> bool {
    f64::is_sign_negative(u0 * v1 - u1 * v0)
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::is_point_inside_triangle;
    use crate::StrError;
    use plotpy::{Canvas, Plot, PolyCode, Text};

    fn draw_triangles(plot: &mut Plot, triangles: &[[[f64; 2]; 3]]) {
        let mut ids = Text::new();
        let mut canvas = Canvas::new();
        canvas.set_face_color("#fefddc80").set_edge_color("#fcb827");
        for t in 0..triangles.len() {
            let (mut xc, mut yc) = (0.0, 0.0);
            canvas.polycurve_begin();
            for m in 0..3 {
                let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
                canvas.polycurve_add(&triangles[t][m][0], &triangles[t][m][1], code);
                xc += triangles[t][m][0];
                yc += triangles[t][m][1];
            }
            canvas.polycurve_end(true);
            xc /= 3.0;
            yc /= 3.0;
            ids.draw(xc, yc, format!("{}", t).as_str());
        }
        plot.add(&canvas).add(&ids);
    }

    #[test]
    #[rustfmt::skip]
    fn is_point_inside_triangle_works_1() {
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.0, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 1.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.5, 0.5]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.5, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 0.5]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.3, 0.3]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1e-15, 1e-15]));
        // assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1e-15, -1e-15])); // imprecision is not accepted
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.1, 0.0]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 1.1]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.0, 1.0]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[-1e-15, -1e-15]));
    }

    #[test]
    fn is_point_inside_triangle_works_2() -> Result<(), StrError> {
        #[rustfmt::skip]
        const T: [[[f64; 2]; 3]; 12] = [
            [[0.230951,  0.558482], [0.133721,  0.348832],   [0.540745,  0.331184]],   //  0
            [[0.13928,   0.180603], [0.133721,  0.348832],   [0.0307942, 0.459123]],   //  1
            [[0.0307942, 0.459123], [0.230951,  0.558482],   [0.0980015, 0.981755]],   //  2
            [[0.230951,  0.558482], [0.0307942, 0.459123],   [0.133721,  0.348832]],   //  3
            [[0.0980015, 0.981755], [0.230951,  0.558482],   [0.578587,  0.760349]],   //  4
            [[0.133721,  0.348832], [0.13928,   0.180603],   [0.540745,  0.331184]],   //  5
            [[0.540745,  0.331184], [0.578587,  0.760349],   [0.230951,  0.558482]],   //  6
            [[0.540745,  0.331184], [0.478554,  0.00869692], [0.648071,  0.369534]],   //  7
            [[0.578587,  0.760349], [0.648071,  0.369534],   [0.903726,  0.975904]],   //  8
            [[0.648071,  0.369534], [0.578587,  0.760349],   [0.540745,  0.331184]],   //  9
            [[0.578587,  0.760349], [0.903726,  0.975904],   [0.0980015, 0.981755]],   // 10
            [[0.540745,  0.331184], [0.13928,   0.180603],   [0.478554,  0.00869692]], // 11
        ];
        for tri in &T {
            for m in 0..3 {
                assert!(is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &tri[m]));
            }
            assert!(!is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &[0.1, 0.1]));
            assert!(!is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &[0.6, 0.2]));
        }
        assert!(is_point_inside_triangle(&T[0][0], &T[0][1], &T[0][2], &[0.3, 0.4]));
        assert!(is_point_inside_triangle(&T[8][0], &T[8][1], &T[8][2], &[0.7, 0.7]));
        if false {
            let mut plot = Plot::new();
            draw_triangles(&mut plot, &T);
            plot.grid_and_labels("x", "y")
                .set_range(0.0, 1.0, 0.0, 1.0)
                .set_ticks_x(0.1, 0.5, "")
                .set_ticks_y(0.1, 0.5, "")
                .set_equal_axes(true)
                .set_figure_size_points(600.0, 600.0)
                .save("/tmp/gemlab/test_is_point_inside_triangle_2.svg")?;
        }
        Ok(())
    }
}
<commit_msg>Impl triangle area<commit_after>/// Returns true if the sign of the cross product vector is negative, including -0.0
///
/// Specifically, returns true if the sign of the component of the out-of-plane vector,
/// resulting from the cross product between u and v is negative
#[inline]
fn cross_is_negative(u0: f64, u1: f64, v0: f64, v1: f64) -> bool {
    f64::is_sign_negative(u0 * v1 - u1 * v0)
}

/// Checks whether a point is inside a triangle or not
///
/// ```text
/// →   →    →    →   →    →    →   →    →
/// a = AB × AP;  b = BC × BP;  c = CA × CP
///
/// The point is inside iff:
///     sign(a[2]) == sign(b[2]) == sign(c[2])
///
/// A,                      A, -------P   OUTSIDE
/// |\',                    | ',     / |
/// | \ ',                  |   ',  /    .
/// |  \  ',                |     ',      .
/// |   \   ',              |     / ',     .
/// |    P.   ',            |    /    ',    |
/// |   /  '.   ',          |   /       ',   .
/// |  /     `-.  ',        |  /          ',  |
/// | /  INSIDE `-. ',      | /             ', .
/// |/             `-.',    |/                ',|
/// C-------------------B   C-------------------B
/// ```
///
/// **Note:** This function returns true if the point is
/// on any boundary or coincides with any vertex
pub fn is_point_inside_triangle(xa: &[f64], xb: &[f64], xc: &[f64], xp: &[f64]) -> bool {
    if (xp[0] == xa[0] && xp[1] == xa[1]) || (xp[0] == xb[0] && xp[1] == xb[1]) || (xp[0] == xc[0] && xp[1] == xc[1]) {
        return true;
    }
    let na = cross_is_negative(xb[0] - xa[0], xb[1] - xa[1], xp[0] - xa[0], xp[1] - xa[1]);
    let nb = cross_is_negative(xc[0] - xb[0], xc[1] - xb[1], xp[0] - xb[0], xp[1] - xb[1]);
    let nc = cross_is_negative(xa[0] - xc[0], xa[1] - xc[1], xp[0] - xc[0], xp[1] - xc[1]);
    (na && nb && nc) || (!na && !nb && !nc)
}

/// Computes the signed area of a triangle given its vertices
///
/// The sign is positive if the vertices are given in counter-clockwise order.
/// Otherwise, the area is negative (clockwise order).
#[rustfmt::skip]
pub fn triangle_signed_area(xa: &[f64], xb: &[f64], xc: &[f64]) -> f64 {
    (   xa[0] * (xb[1] - xc[1])
      + xb[0] * (xc[1] - xa[1])
      + xc[0] * (xa[1] - xb[1])
    ) / 2.0
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{is_point_inside_triangle, triangle_signed_area};
    use crate::StrError;
    use plotpy::{Canvas, Plot, PolyCode, Text};

    fn draw_triangles(plot: &mut Plot, triangles: &[[[f64; 2]; 3]]) {
        let mut ids = Text::new();
        let mut canvas = Canvas::new();
        canvas.set_face_color("#fefddc80").set_edge_color("#fcb827");
        for t in 0..triangles.len() {
            let (mut xc, mut yc) = (0.0, 0.0);
            canvas.polycurve_begin();
            for m in 0..3 {
                let code = if m == 0 { PolyCode::MoveTo } else { PolyCode::LineTo };
                canvas.polycurve_add(&triangles[t][m][0], &triangles[t][m][1], code);
                xc += triangles[t][m][0];
                yc += triangles[t][m][1];
            }
            canvas.polycurve_end(true);
            xc /= 3.0;
            yc /= 3.0;
            ids.draw(xc, yc, format!("{}", t).as_str());
        }
        plot.add(&canvas).add(&ids);
    }

    #[test]
    #[rustfmt::skip]
    fn is_point_inside_triangle_works_1() {
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.0, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 1.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.5, 0.5]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.5, 0.0]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 0.5]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.3, 0.3]));
        assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1e-15, 1e-15]));
        // assert!(is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1e-15, -1e-15])); // imprecision is not accepted
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.1, 0.0]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[0.0, 1.1]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[1.0, 1.0]));
        assert!(!is_point_inside_triangle(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0], &[-1e-15, -1e-15]));
    }

    #[test]
    fn is_point_inside_triangle_works_2() -> Result<(), StrError> {
        #[rustfmt::skip]
        const T: [[[f64; 2]; 3]; 12] = [
            [[0.230951,  0.558482], [0.133721,  0.348832],   [0.540745,  0.331184]],   //  0
            [[0.13928,   0.180603], [0.133721,  0.348832],   [0.0307942, 0.459123]],   //  1
            [[0.0307942, 0.459123], [0.230951,  0.558482],   [0.0980015, 0.981755]],   //  2
            [[0.230951,  0.558482], [0.0307942, 0.459123],   [0.133721,  0.348832]],   //  3
            [[0.0980015, 0.981755], [0.230951,  0.558482],   [0.578587,  0.760349]],   //  4
            [[0.133721,  0.348832], [0.13928,   0.180603],   [0.540745,  0.331184]],   //  5
            [[0.540745,  0.331184], [0.578587,  0.760349],   [0.230951,  0.558482]],   //  6
            [[0.540745,  0.331184], [0.478554,  0.00869692], [0.648071,  0.369534]],   //  7
            [[0.578587,  0.760349], [0.648071,  0.369534],   [0.903726,  0.975904]],   //  8
            [[0.648071,  0.369534], [0.578587,  0.760349],   [0.540745,  0.331184]],   //  9
            [[0.578587,  0.760349], [0.903726,  0.975904],   [0.0980015, 0.981755]],   // 10
            [[0.540745,  0.331184], [0.13928,   0.180603],   [0.478554,  0.00869692]], // 11
        ];
        for tri in &T {
            for m in 0..3 {
                assert!(is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &tri[m]));
            }
            assert!(!is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &[0.1, 0.1]));
            assert!(!is_point_inside_triangle(&tri[0], &tri[1], &tri[2], &[0.6, 0.2]));
        }
        assert!(is_point_inside_triangle(&T[0][0], &T[0][1], &T[0][2], &[0.3, 0.4]));
        assert!(is_point_inside_triangle(&T[8][0], &T[8][1], &T[8][2], &[0.7, 0.7]));
        if false {
            let mut plot = Plot::new();
            draw_triangles(&mut plot, &T);
            plot.grid_and_labels("x", "y")
                .set_range(0.0, 1.0, 0.0, 1.0)
                .set_ticks_x(0.1, 0.5, "")
                .set_ticks_y(0.1, 0.5, "")
                .set_equal_axes(true)
                .set_figure_size_points(600.0, 600.0)
                .save("/tmp/gemlab/test_is_point_inside_triangle_2.svg")?;
        }
        Ok(())
    }

    #[test]
    fn triangle_signed_area_works() {
        assert_eq!(triangle_signed_area(&[0.0, 0.0], &[1.0, 0.0], &[0.0, 1.0]), 0.5);
        assert_eq!(triangle_signed_area(&[1.0, 0.0], &[0.0, 0.0], &[0.0, 1.0]), -0.5);
        assert_eq!(triangle_signed_area(&[-1.0, 2.0], &[4.0, -3.0], &[2.0, 3.0]), 10.0);
        assert_eq!(triangle_signed_area(&[-2.0, 3.0], &[-3.0, -1.0], &[3.0, -2.0]), 12.5);
    }
}
<|endoftext|>


<commit_before>//! OpenGL rendering types

use nix::libc::c_void;

use super::{PixelFormat, SwapBuffersError};

#[allow(clippy::all, rust_2018_idioms, missing_docs)]
pub(crate) mod ffi {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

pub use self::ffi::Gles2;

/// Trait that describes objects that have an OpenGL context
/// and can be used to render upon
pub trait GLGraphicsBackend {
    /// Swaps buffers at the end of a frame.
    fn swap_buffers(&self) -> Result<(), SwapBuffersError>;

    /// Returns the address of an OpenGL function.
    fn get_proc_address(&self, symbol: &str) -> *const c_void;

    /// Returns the dimensions of the window, or screen, etc in points.
    ///
    /// These are the actual pixels of the underlying graphics backend.
    /// For nested compositors you will need to handle the scaling
    /// of the root compositor yourself, if you want to.
    fn get_framebuffer_dimensions(&self) -> (u32, u32);

    /// Returns true if the OpenGL context is the current one in the thread.
    fn is_current(&self) -> bool;

    /// Makes the OpenGL context the current context in the current thread.
    ///
    /// # Safety
    ///
    /// The context cannot be made current on multiple threads.
    unsafe fn make_current(&self) -> Result<(), SwapBuffersError>;

    /// Returns the pixel format of the main framebuffer of the context.
    fn get_pixel_format(&self) -> PixelFormat;
}

/// Loads a Raw GLES Interface for a given [`GLGraphicsBackend`]
///
/// This remains valid as long as the underlying [`GLGraphicsBackend`] is alive
/// and may only be used in combination with the backend. Using this with any
/// other gl context or after the backend was dropped *may* cause undefined behavior.
pub fn load_raw_gl<B: GLGraphicsBackend>(backend: &B) -> Gles2 {
    Gles2::load_with(|s| { backend.get_proc_address(s) as *const _ })
}
<commit_msg>Fix formatting<commit_after>//! OpenGL rendering types

use nix::libc::c_void;

use super::{PixelFormat, SwapBuffersError};

#[allow(clippy::all, rust_2018_idioms, missing_docs)]
pub(crate) mod ffi {
    include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
}

pub use self::ffi::Gles2;

/// Trait that describes objects that have an OpenGL context
/// and can be used to render upon
pub trait GLGraphicsBackend {
    /// Swaps buffers at the end of a frame.
    fn swap_buffers(&self) -> Result<(), SwapBuffersError>;

    /// Returns the address of an OpenGL function.
    fn get_proc_address(&self, symbol: &str) -> *const c_void;

    /// Returns the dimensions of the window, or screen, etc in points.
    ///
    /// These are the actual pixels of the underlying graphics backend.
    /// For nested compositors you will need to handle the scaling
    /// of the root compositor yourself, if you want to.
    fn get_framebuffer_dimensions(&self) -> (u32, u32);

    /// Returns true if the OpenGL context is the current one in the thread.
    fn is_current(&self) -> bool;

    /// Makes the OpenGL context the current context in the current thread.
    ///
    /// # Safety
    ///
    /// The context cannot be made current on multiple threads.
    unsafe fn make_current(&self) -> Result<(), SwapBuffersError>;

    /// Returns the pixel format of the main framebuffer of the context.
    fn get_pixel_format(&self) -> PixelFormat;
}

/// Loads a Raw GLES Interface for a given [`GLGraphicsBackend`]
///
/// This remains valid as long as the underlying [`GLGraphicsBackend`] is alive
/// and may only be used in combination with the backend. Using this with any
/// other gl context or after the backend was dropped *may* cause undefined behavior.
pub fn load_raw_gl<B: GLGraphicsBackend>(backend: &B) -> Gles2 {
    Gles2::load_with(|s| backend.get_proc_address(s) as *const _)
}
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Launching", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    let mut methods = Vec::new();
    // trying $BROWSER
    match env::var("BROWSER"){
        Ok(name) => match Command::new(name).arg(path).status() {
            Ok(_) => return Ok("$BROWSER"),
            Err(_) => methods.push("$BROWSER")
        },
        Err(_) => () // Do nothing here if $BROWSER is not found
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m)
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return Ok("cmd /C start"),
        Err(_) => return Err(vec!["cmd /C start"])
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"])
    };
}
<commit_msg>Don't include env in windows/macos<commit_after>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::{Package, PackageIdSpec};
use ops;
use util::CargoResult;

pub struct DocOptions<'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let package = try!(Package::for_path(manifest_path, options.compile_opts.config));

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_empty() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.crate_name()));
            } else {
                assert!(bin_names.insert(target.crate_name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                bail!("cannot document a package where a library and a binary \
                       have the same name. Consider renaming one or marking \
                       the target as `doc = false`")
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = if options.compile_opts.spec.len() > 1 {
            bail!("Passing multiple packages and `open` is not supported")
        } else if options.compile_opts.spec.len() == 1 {
            try!(PackageIdSpec::parse(&options.compile_opts.spec[0]))
                                             .name().replace("-", "_")
        } else {
            match lib_names.iter().chain(bin_names.iter()).nth(0) {
                Some(s) => s.to_string(),
                None => return Ok(())
            }
        };

        let target_dir = options.compile_opts.config.target_dir(&package);
        let path = target_dir.join("doc").join(&name).join("index.html");
        if fs::metadata(&path).is_ok() {
            let mut shell = options.compile_opts.config.shell();
            match open_docs(&path) {
                Ok(m) => try!(shell.status("Launching", m)),
                Err(e) => {
                    try!(shell.warn(
                            "warning: could not determine a browser to open docs with, tried:"));
                    for method in e {
                        try!(shell.warn(format!("\t{}", method)));
                    }
                }
            }
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    use std::env;
    let mut methods = Vec::new();
    // trying $BROWSER
    match env::var("BROWSER"){
        Ok(name) => match Command::new(name).arg(path).status() {
            Ok(_) => return Ok("$BROWSER"),
            Err(_) => methods.push("$BROWSER")
        },
        Err(_) => () // Do nothing here if $BROWSER is not found
    }

    for m in ["xdg-open", "gnome-open", "kde-open"].iter() {
        match Command::new(m).arg(path).status() {
            Ok(_) => return Ok(m),
            Err(_) => methods.push(m)
        }
    }

    Err(methods)
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("cmd").arg("/C").arg("start").arg("").arg(path).status() {
        Ok(_) => return Ok("cmd /C start"),
        Err(_) => return Err(vec!["cmd /C start"])
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) -> Result<&'static str, Vec<&'static str>> {
    match Command::new("open").arg(path).status() {
        Ok(_) => return Ok("open"),
        Err(_) => return Err(vec!["open"])
    };
}
<|endoftext|>


<commit_before>use std::cmp;
use std::iter;
use std::time::{Instant, Duration};

use util::{Config, CargoResult};

pub struct Progress<'cfg> {
    state: Option<State<'cfg>>,
}

struct State<'cfg> {
    config: &'cfg Config,
    width: usize,
    first: bool,
    last_update: Instant,
    name: String,
    done: bool,
}

impl<'cfg> Progress<'cfg> {
    pub fn new(name: &str, cfg: &'cfg Config) -> Progress<'cfg> {
        Progress {
            state: cfg.shell().err_width().map(|n| {
                State {
                    config: cfg,
                    width: cmp::min(n, 80),
                    first: true,
                    last_update: Instant::now(),
                    name: name.to_string(),
                    done: false,
                }
            }),
        }
    }

    pub fn tick(&mut self, cur: usize, max: usize) -> CargoResult<()> {
        match self.state {
            Some(ref mut s) => s.tick(cur, max),
            None => Ok(())
        }
    }
}

impl<'cfg> State<'cfg> {
    fn tick(&mut self, cur: usize, max: usize) -> CargoResult<()> {
        if self.done {
            return Ok(())
        }

        // Don't update too often as it can cause excessive performance loss
        // just putting stuff onto the terminal. We also want to avoid
        // flickering by not drawing anything that goes away too quickly. As a
        // result we've got two branches here:
        //
        // 1. If we haven't drawn anything, we wait for a period of time to
        //    actually start drawing to the console. This ensures that
        //    short-lived operations don't flicker on the console. Currently
        //    there's a 500ms delay to when we first draw something.
        // 2. If we've drawn something, then we rate limit ourselves to only
        //    draw to the console every so often. Currently there's a 100ms
        //    delay between updates.
        if self.first {
            let delay = Duration::from_millis(500);
            if self.last_update.elapsed() < delay {
                return Ok(())
            }
            self.first = false;
        } else {
            let interval = Duration::from_millis(100);
            if self.last_update.elapsed() < interval {
                return Ok(())
            }
        }
        self.last_update = Instant::now();

        // Render the percentage at the far right and then figure how long the
        // progress bar is
        let pct = (cur as f64) / (max as f64);
        let pct = if !pct.is_finite() { 0.0 } else { pct };
        let stats = format!(" {:6.02}%", pct * 100.0);
        let extra_len = stats.len() + 2 /* [ and ] */ + 15 /* status header */;
        let display_width = match self.width.checked_sub(extra_len) {
            Some(n) => n,
            None => return Ok(()),
        };
        let mut string = String::from("[");
        let hashes = display_width as f64 * pct;
        let hashes = hashes as usize;

        // Draw the `===>`
        if hashes > 0 {
            for _ in 0..hashes-1 {
                string.push_str("=");
            }
            if cur == max {
                self.done = true;
                string.push_str("=");
            } else {
                string.push_str(">");
            }
        }

        // Draw the empty space we have left to do
        for _ in 0..(display_width - hashes) {
            string.push_str(" ");
        }
        string.push_str("]");
        string.push_str(&stats);

        // Write out a pretty header, then the progress bar itself, and then
        // return back to the beginning of the line for the next print.
        self.config.shell().status_header(&self.name)?;
        write!(self.config.shell().err(), "{}\r", string)?;
        Ok(())
    }
}

fn clear(width: usize, config: &Config) {
    let blank = iter::repeat(" ").take(width).collect::<String>();
    drop(write!(config.shell().err(), "{}\r", blank));
}

impl<'cfg> Drop for State<'cfg> {
    fn drop(&mut self) {
        clear(self.width, self.config);
    }
}
<commit_msg>Auto merge of #4826 - alexcrichton:silence-progress, r=matklad<commit_after>use std::cmp;
use std::iter;
use std::time::{Instant, Duration};

use core::shell::Verbosity;
use util::{Config, CargoResult};

pub struct Progress<'cfg> {
    state: Option<State<'cfg>>,
}

struct State<'cfg> {
    config: &'cfg Config,
    width: usize,
    first: bool,
    last_update: Instant,
    name: String,
    done: bool,
}

impl<'cfg> Progress<'cfg> {
    pub fn new(name: &str, cfg: &'cfg Config) -> Progress<'cfg> {
        // no progress if `-q` is passed as, well, we're supposed to be quiet
        if cfg.shell().verbosity() == Verbosity::Quiet {
            return Progress { state: None }
        }

        Progress {
            state: cfg.shell().err_width().map(|n| {
                State {
                    config: cfg,
                    width: cmp::min(n, 80),
                    first: true,
                    last_update: Instant::now(),
                    name: name.to_string(),
                    done: false,
                }
            }),
        }
    }

    pub fn tick(&mut self, cur: usize, max: usize) -> CargoResult<()> {
        match self.state {
            Some(ref mut s) => s.tick(cur, max),
            None => Ok(())
        }
    }
}

impl<'cfg> State<'cfg> {
    fn tick(&mut self, cur: usize, max: usize) -> CargoResult<()> {
        if self.done {
            return Ok(())
        }

        // Don't update too often as it can cause excessive performance loss
        // just putting stuff onto the terminal. We also want to avoid
        // flickering by not drawing anything that goes away too quickly. As a
        // result we've got two branches here:
        //
        // 1. If we haven't drawn anything, we wait for a period of time to
        //    actually start drawing to the console. This ensures that
        //    short-lived operations don't flicker on the console. Currently
        //    there's a 500ms delay to when we first draw something.
        // 2. If we've drawn something, then we rate limit ourselves to only
        //    draw to the console every so often. Currently there's a 100ms
        //    delay between updates.
        if self.first {
            let delay = Duration::from_millis(500);
            if self.last_update.elapsed() < delay {
                return Ok(())
            }
            self.first = false;
        } else {
            let interval = Duration::from_millis(100);
            if self.last_update.elapsed() < interval {
                return Ok(())
            }
        }
        self.last_update = Instant::now();

        // Render the percentage at the far right and then figure how long the
        // progress bar is
        let pct = (cur as f64) / (max as f64);
        let pct = if !pct.is_finite() { 0.0 } else { pct };
        let stats = format!(" {:6.02}%", pct * 100.0);
        let extra_len = stats.len() + 2 /* [ and ] */ + 15 /* status header */;
        let display_width = match self.width.checked_sub(extra_len) {
            Some(n) => n,
            None => return Ok(()),
        };
        let mut string = String::from("[");
        let hashes = display_width as f64 * pct;
        let hashes = hashes as usize;

        // Draw the `===>`
        if hashes > 0 {
            for _ in 0..hashes-1 {
                string.push_str("=");
            }
            if cur == max {
                self.done = true;
                string.push_str("=");
            } else {
                string.push_str(">");
            }
        }

        // Draw the empty space we have left to do
        for _ in 0..(display_width - hashes) {
            string.push_str(" ");
        }
        string.push_str("]");
        string.push_str(&stats);

        // Write out a pretty header, then the progress bar itself, and then
        // return back to the beginning of the line for the next print.
        self.config.shell().status_header(&self.name)?;
        write!(self.config.shell().err(), "{}\r", string)?;
        Ok(())
    }
}

fn clear(width: usize, config: &Config) {
    let blank = iter::repeat(" ").take(width).collect::<String>();
    drop(write!(config.shell().err(), "{}\r", blank));
}

impl<'cfg> Drop for State<'cfg> {
    fn drop(&mut self) {
        clear(self.width, self.config);
    }
}
<|endoftext|>


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

use log::debug;
use serde::Serialize;
use serde_yaml;

use crate::error::*;

use super::assets;
use super::collection;
use super::mark;
use super::site;
use super::template;
use super::vwiki;
use crate::SyntaxHighlight;

#[derive(Debug, Clone, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
    pub source: path::PathBuf,
    pub destination: path::PathBuf,
    pub ignore: Vec<liquid::model::KString>,
    pub page_extensions: Vec<liquid::model::KString>,
    pub include_drafts: bool,
    pub pages: collection::Collection,
    pub posts: collection::Collection,
    pub site: site::Site,
    pub layouts_path: path::PathBuf,
    pub liquid: template::LiquidBuilder,
    pub markdown: mark::MarkdownBuilder,
    pub vimwiki: vwiki::VimwikiBuilder,
    #[serde(skip)]
    pub syntax: std::sync::Arc<SyntaxHighlight>,
    pub assets: assets::AssetsBuilder,
    pub minify: cobalt_config::Minify,
}

impl Config {
    pub fn from_config(source: cobalt_config::Config) -> Result<Self> {
        let cobalt_config::Config {
            root,
            source,
            destination,
            abs_dest,
            include_drafts,
            default,
            pages,
            posts,
            site,
            template_extensions,
            ignore: custom_ignore,
            syntax_highlight,
            layouts_dir,
            includes_dir,
            assets,
            minify,
        } = source;

        if include_drafts {
            debug!("Draft mode enabled");
        }

        if template_extensions.is_empty() {
            failure::bail!("`template_extensions` should not be empty.");
        }

        let source = source.to_path(&root);
        let destination = abs_dest.unwrap_or_else(|| destination.to_path(root));

        let pages = collection::Collection::from_page_config(pages, &site, &default)?;

        let posts =
            collection::Collection::from_post_config(posts, &site, include_drafts, &default)?;

        let site = site::Site::from_config(site);

        let mut ignore: Vec<liquid::model::KString> = vec![".*".into(), "_*".into()];
        if let Ok(rel_dest) = path::Path::new(&destination).strip_prefix(&source) {
            let rel_dest = rel_dest.to_str().expect("started as a utf-8 string");
            if !rel_dest.is_empty() {
                ignore.push(format!("/{}", rel_dest.to_owned()).into());
            }
        }
        ignore.push(format!("/{}", includes_dir).into());
        ignore.push(format!("/{}", layouts_dir).into());
        ignore.push("/_defaults".into());
        ignore.push(format!("/{}", assets.sass.import_dir).into());
        assert_eq!(pages.dir, "");
        assert_eq!(pages.drafts_dir, None);
        ignore.push(format!("!/{}", posts.dir).into());
        if let Some(dir) = posts.drafts_dir.as_deref() {
            ignore.push(format!("!/{}", dir).into());
        }
        ignore.extend(custom_ignore);

        let assets = assets::AssetsBuilder::from_config(assets, &source);

        let includes_path = source.join(includes_dir);
        let layouts_path = source.join(layouts_dir);

        let syntax = std::sync::Arc::new(SyntaxHighlight::new());

        let liquid = template::LiquidBuilder {
            includes_path,
            syntax: syntax.clone(),
            theme: syntax_highlight
                .enabled
                .then(|| syntax_highlight.theme.clone()),
        };
        let markdown = mark::MarkdownBuilder {
            syntax: syntax.clone(),
            theme: syntax_highlight
                .enabled
                .then(|| syntax_highlight.theme.clone()),
        };
        let vimwiki = vwiki::VimwikiBuilder {
            theme: syntax_highlight.theme,
            syntax_highlight_enabled: syntax_highlight.enabled,
        };

        let config = Config {
            source,
            destination,
            ignore,
            page_extensions: template_extensions,
            include_drafts,
            pages,
            posts,
            site,
            layouts_path,
            liquid,
            markdown,
            vimwiki,
            syntax,
            assets,
            minify,
        };

        Ok(config)
    }
}

impl Default for Config {
    fn default() -> Config {
        Config::from_config(cobalt_config::Config::default())
            .expect("default config should not fail")
    }
}

impl fmt::Display for Config {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut converted = serde_yaml::to_string(self).map_err(|_| fmt::Error)?;
        converted.drain(..4);
        write!(f, "{}", converted)
    }
}

#[test]
fn test_build_default() {
    let config = cobalt_config::Config::default();
    Config::from_config(config).unwrap();
}

#[test]
fn test_build_dest() {
    let config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
    let result = Config::from_config(config).unwrap();
    assert_eq!(
        result.source,
        path::Path::new("tests/fixtures/config").to_path_buf()
    );
    assert_eq!(
        result.destination,
        path::Path::new("tests/fixtures/config/dest").to_path_buf()
    );
}

#[test]
fn test_build_abs_dest() {
    let mut config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
    config.abs_dest = Some(path::PathBuf::from("hello/world"));
    let result = Config::from_config(config).unwrap();
    assert_eq!(
        result.source,
        path::Path::new("tests/fixtures/config").to_path_buf()
    );
    assert_eq!(
        result.destination,
        path::Path::new("hello/world").to_path_buf()
    );
}
<commit_msg>load custom syntaxes in config<commit_after>use std::fmt;
use std::path;

use log::debug;
use serde::Serialize;
use serde_yaml;

use crate::error::*;

use super::assets;
use super::collection;
use super::mark;
use super::site;
use super::template;
use super::vwiki;
use crate::SyntaxHighlight;

#[derive(Debug, Clone, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct Config {
    pub source: path::PathBuf,
    pub destination: path::PathBuf,
    pub ignore: Vec<liquid::model::KString>,
    pub page_extensions: Vec<liquid::model::KString>,
    pub include_drafts: bool,
    pub pages: collection::Collection,
    pub posts: collection::Collection,
    pub site: site::Site,
    pub layouts_path: path::PathBuf,
    pub liquid: template::LiquidBuilder,
    pub markdown: mark::MarkdownBuilder,
    pub vimwiki: vwiki::VimwikiBuilder,
    #[serde(skip)]
    pub syntax: std::sync::Arc<SyntaxHighlight>,
    pub assets: assets::AssetsBuilder,
    pub minify: cobalt_config::Minify,
}

impl Config {
    pub fn from_config(source: cobalt_config::Config) -> Result<Self> {
        let cobalt_config::Config {
            root,
            source,
            destination,
            abs_dest,
            include_drafts,
            default,
            pages,
            posts,
            site,
            template_extensions,
            ignore: custom_ignore,
            syntax_highlight,
            layouts_dir,
            includes_dir,
            assets,
            minify,
        } = source;

        if include_drafts {
            debug!("Draft mode enabled");
        }

        if template_extensions.is_empty() {
            failure::bail!("`template_extensions` should not be empty.");
        }

        let source = source.to_path(&root);
        let destination = abs_dest.unwrap_or_else(|| destination.to_path(root));

        let pages = collection::Collection::from_page_config(pages, &site, &default)?;

        let posts =
            collection::Collection::from_post_config(posts, &site, include_drafts, &default)?;

        let site = site::Site::from_config(site);

        let mut ignore: Vec<liquid::model::KString> = vec![".*".into(), "_*".into()];
        if let Ok(rel_dest) = path::Path::new(&destination).strip_prefix(&source) {
            let rel_dest = rel_dest.to_str().expect("started as a utf-8 string");
            if !rel_dest.is_empty() {
                ignore.push(format!("/{}", rel_dest.to_owned()).into());
            }
        }
        ignore.push(format!("/{}", includes_dir).into());
        ignore.push(format!("/{}", layouts_dir).into());
        ignore.push("/_defaults".into());
        ignore.push(format!("/{}", assets.sass.import_dir).into());
        assert_eq!(pages.dir, "");
        assert_eq!(pages.drafts_dir, None);
        ignore.push(format!("!/{}", posts.dir).into());
        if let Some(dir) = posts.drafts_dir.as_deref() {
            ignore.push(format!("!/{}", dir).into());
        }
        ignore.extend(custom_ignore);

        let assets = assets::AssetsBuilder::from_config(assets, &source);

        let includes_path = source.join(includes_dir);
        let layouts_path = source.join(layouts_dir);

        let mut highlight = SyntaxHighlight::new();
        let syntaxes_path = source.join("_syntaxes");
        if syntaxes_path.exists() {
            highlight.load_custom_syntaxes(&syntaxes_path);
        }

        let syntax = std::sync::Arc::new(highlight);

        let liquid = template::LiquidBuilder {
            includes_path,
            syntax: syntax.clone(),
            theme: syntax_highlight
                .enabled
                .then(|| syntax_highlight.theme.clone()),
        };
        let markdown = mark::MarkdownBuilder {
            syntax: syntax.clone(),
            theme: syntax_highlight
                .enabled
                .then(|| syntax_highlight.theme.clone()),
        };
        let vimwiki = vwiki::VimwikiBuilder {
            theme: syntax_highlight.theme,
            syntax_highlight_enabled: syntax_highlight.enabled,
        };

        let config = Config {
            source,
            destination,
            ignore,
            page_extensions: template_extensions,
            include_drafts,
            pages,
            posts,
            site,
            layouts_path,
            liquid,
            markdown,
            vimwiki,
            syntax,
            assets,
            minify,
        };

        Ok(config)
    }
}

impl Default for Config {
    fn default() -> Config {
        Config::from_config(cobalt_config::Config::default())
            .expect("default config should not fail")
    }
}

impl fmt::Display for Config {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut converted = serde_yaml::to_string(self).map_err(|_| fmt::Error)?;
        converted.drain(..4);
        write!(f, "{}", converted)
    }
}

#[test]
fn test_build_default() {
    let config = cobalt_config::Config::default();
    Config::from_config(config).unwrap();
}

#[test]
fn test_build_dest() {
    let config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
    let result = Config::from_config(config).unwrap();
    assert_eq!(
        result.source,
        path::Path::new("tests/fixtures/config").to_path_buf()
    );
    assert_eq!(
        result.destination,
        path::Path::new("tests/fixtures/config/dest").to_path_buf()
    );
}

#[test]
fn test_build_abs_dest() {
    let mut config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
    config.abs_dest = Some(path::PathBuf::from("hello/world"));
    let result = Config::from_config(config).unwrap();
    assert_eq!(
        result.source,
        path::Path::new("tests/fixtures/config").to_path_buf()
    );
    assert_eq!(
        result.destination,
        path::Path::new("hello/world").to_path_buf()
    );
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"#![allow(dead_code)]",
"",
"extern crate libc;",
"extern crate glib_sys as glib_ffi;",
"extern crate gdk_sys as gdk_ffi;",
"extern crate pango_sys as pango_ffi;",
"",
"pub mod enums;",
"",
"use libc::{c_int, c_char, c_float, c_uint, c_double, c_long, c_void, time_t};",
"",
"pub use glib_ffi::{",
"    gboolean, GFALSE, GTRUE, gsize, gpointer, GType, GObject, GPermission,",
"    GList, GSList, GError, GValue};",
"",
"#[repr(C)]",
"pub struct GAppLaunchContext;",
"#[repr(C)]",
"pub struct GAppInfo;",
"//pub struct GtkPageSetupUnixDialog;",
"#[repr(C)]",
"pub struct GtkPaperSize;",
"#[repr(C)]",
"pub struct GtkRecentInfo;",
"#[repr(C)]",
"pub struct GtkTreePath;",
"#[repr(C)]",
"pub struct GMenuModel;",
"#[repr(C)]",
"pub struct GClosure;",
"#[repr(C)]",
"pub struct GtkTextAttributes;",
"#[repr(C)]",
"pub struct GtkIconSize;",
"#[repr(C)]",
"pub struct GtkTextIter;",
"#[repr(C)]",
"pub struct GtkMovementStep;",
    ];

    write_vec(w, &v)
}

pub fn before_func<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[repr(C)]",
"pub struct GtkRecentData {",
"    pub display_name: *mut c_char,",
"    pub description: *mut c_char,",
"    pub mime_type: *mut c_char,",
"    pub app_name: *mut c_char,",
"    pub app_exec: *mut c_char,",
"    pub groups: *mut *mut c_char,",
"    pub is_private: gboolean",
"}",
"#[repr(C)]",
"pub struct GtkRecentFilterInfo {",
"    pub contains: enums::RecentFilterFlags,",
"    pub uri: *const c_char,",
"    pub display_name: *const c_char,",
"    pub mime_type: *const c_char,",
"    pub applications: *const *const c_char,",
"    pub groups: *const *const c_char,",
"    pub age: c_int",
"}",
"#[repr(C)]",
"pub struct GtkTreeIter {",
"    pub stamp: c_int,",
"    pub user_data: *mut c_void,",
"    pub user_data2: *mut c_void,",
"    pub user_data3: *mut c_void",
"}",
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<commit_msg>Move records to bottom, remove enums, mark others.<commit_after>use std::io::{Result, Write};

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"#![allow(dead_code)]",
"",
"extern crate libc;",
"extern crate glib_sys as glib_ffi;",
"extern crate gdk_sys as gdk_ffi;",
"extern crate pango_sys as pango_ffi;",
"",
"pub mod enums;",
"",
"use libc::{c_int, c_char, c_float, c_uint, c_double, c_long, c_void, time_t};",
"",
"pub use glib_ffi::{",
"    gboolean, GFALSE, GTRUE, gsize, gpointer, GType, GObject, GPermission,",
"    GList, GSList, GError, GValue};",
    ];

    write_vec(w, &v)
}

pub fn before_func<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[repr(C)]",
"pub struct GtkPaperSize; //boxed",
"#[repr(C)]",
"pub struct GtkTextIter; //boxed",
"#[repr(C)]",
"pub struct GtkTreePath; //boxed",
"#[repr(C)]",
"pub struct GtkTextAttributes;",
"#[repr(C)]",
"pub struct GtkRecentInfo;",
"#[repr(C)]",
"pub struct GtkRecentData {",
"    pub display_name: *mut c_char,",
"    pub description: *mut c_char,",
"    pub mime_type: *mut c_char,",
"    pub app_name: *mut c_char,",
"    pub app_exec: *mut c_char,",
"    pub groups: *mut *mut c_char,",
"    pub is_private: gboolean",
"}",
"#[repr(C)]",
"pub struct GtkRecentFilterInfo {",
"    pub contains: enums::RecentFilterFlags,",
"    pub uri: *const c_char,",
"    pub display_name: *const c_char,",
"    pub mime_type: *const c_char,",
"    pub applications: *const *const c_char,",
"    pub groups: *const *const c_char,",
"    pub age: c_int",
"}",
"#[repr(C)]",
"pub struct GtkTreeIter {",
"    pub stamp: c_int,",
"    pub user_data: *mut c_void,",
"    pub user_data2: *mut c_void,",
"    pub user_data3: *mut c_void",
"}",
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2016 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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 project;
use fips;
use cli::arguments::{pipeline_arg, no_open_arg,
                     value_of, auto_bump, project_specific_args};
use clap::{App, SubCommand, ArgMatches};
use config::Config;
use types::DeliveryResult;
use cli::Options;

pub const SUBCOMMAND_NAME: &'static str = "review";

#[derive(Debug)]
pub struct ReviewClapOptions<'n> {
    pub pipeline: &'n str,
    pub no_open: bool,
    pub auto_bump: bool,
    pub edit: bool,
    pub fips: bool,
    pub fips_git_port: &'n str,
    pub fips_custom_cert_filename: &'n str,
}
impl<'n> Default for ReviewClapOptions<'n> {
    fn default() -> Self {
        ReviewClapOptions {
            pipeline: "master",
            no_open: false,
            auto_bump: false,
            edit: false,
            fips: false,
            fips_git_port: "",
            fips_custom_cert_filename: "",
        }
    }
}

impl<'n> ReviewClapOptions<'n> {
    pub fn new(matches: &'n ArgMatches<'n>) -> Self {
        ReviewClapOptions {
            pipeline: value_of(&matches, "pipeline"),
            no_open: matches.is_present("no-open"),
            auto_bump: matches.is_present("auto-bump"),
            edit: matches.is_present("edit"),
            fips: matches.is_present("fips"),
            fips_git_port: value_of(&matches, "fips-git-port"),
            fips_custom_cert_filename: value_of(&matches, "fips-custom-cert-filename"),
        }
    }
}

impl<'n> Options for ReviewClapOptions<'n> {
    fn merge_options_and_config(&self, config: Config) -> DeliveryResult<Config> {
        let mut new_config = config.set_pipeline(&self.pipeline);

        if new_config.auto_bump.is_none() {
            new_config.auto_bump = Some(self.auto_bump);
        }

        if new_config.project.is_none() {
            new_config.project = project::project_from_cwd().ok();
        }

        fips::merge_fips_options_and_config(self.fips, self.fips_git_port,
                                            self.fips_custom_cert_filename, new_config)
    }
}

pub fn clap_subcommand<'c>() -> App<'c, 'c> {
    SubCommand::with_name(SUBCOMMAND_NAME)
        .about("Submit current branch for review")
        .args(&vec![no_open_arg(), auto_bump()])
        .args_from_usage("-e --edit 'Edit change title and description'")
        .args(&pipeline_arg())
        .args(&project_specific_args())
}
<commit_msg>Added user argument to review command<commit_after>//
// Copyright:: Copyright (c) 2016 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// 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 project;
use fips;
use cli::arguments::{pipeline_arg, no_open_arg,
                     value_of, auto_bump, project_specific_args};
use clap::{App, SubCommand, ArgMatches};
use config::Config;
use types::DeliveryResult;
use cli::Options;

pub const SUBCOMMAND_NAME: &'static str = "review";

#[derive(Debug)]
pub struct ReviewClapOptions<'n> {
    pub pipeline: &'n str,
    pub no_open: bool,
    pub auto_bump: bool,
    pub edit: bool,
    pub fips: bool,
    pub fips_git_port: &'n str,
    pub fips_custom_cert_filename: &'n str,
    pub user: &'n str,
}
impl<'n> Default for ReviewClapOptions<'n> {
    fn default() -> Self {
        ReviewClapOptions {
            pipeline: "master",
            no_open: false,
            auto_bump: false,
            edit: false,
            fips: false,
            fips_git_port: "",
            fips_custom_cert_filename: "",
            user: "",
        }
    }
}

impl<'n> ReviewClapOptions<'n> {
    pub fn new(matches: &'n ArgMatches<'n>) -> Self {
        ReviewClapOptions {
            pipeline: value_of(&matches, "pipeline"),
            no_open: matches.is_present("no-open"),
            auto_bump: matches.is_present("auto-bump"),
            edit: matches.is_present("edit"),
            fips: matches.is_present("fips"),
            fips_git_port: value_of(&matches, "fips-git-port"),
            fips_custom_cert_filename: value_of(&matches, "fips-custom-cert-filename"),
            user: value_of(&matches, "user"),
        }
    }
}

impl<'n> Options for ReviewClapOptions<'n> {
    fn merge_options_and_config(&self, config: Config) -> DeliveryResult<Config> {
        let mut new_config = config.set_pipeline(&self.pipeline)
            .set_user(&self.user);

        if new_config.auto_bump.is_none() {
            new_config.auto_bump = Some(self.auto_bump);
        }

        if new_config.project.is_none() {
            new_config.project = project::project_from_cwd().ok();
        }

        fips::merge_fips_options_and_config(self.fips, self.fips_git_port,
                                            self.fips_custom_cert_filename, new_config)
    }
}

pub fn clap_subcommand<'c>() -> App<'c, 'c> {
    SubCommand::with_name(SUBCOMMAND_NAME)
        .about("Submit current branch for review")
        .args(&vec![no_open_arg(), auto_bump()])
        .args_from_usage("-e --edit 'Edit change title and description'")
        .args(&pipeline_arg())
        .args(&project_specific_args())
        .args_from_usage("-u --user=[user] 'Automate user name for authentication'")
}
<|endoftext|>