<commit_before>//! Global values.

use crate::ir::immediates::{Imm64, Offset32};
use crate::ir::{ExternalName, GlobalValue, Type};
use crate::isa::TargetIsa;
use core::fmt;

/// Information about a global value declaration.
#[derive(Clone)]
pub enum GlobalValueData {
    /// Value is the address of the VM context struct.
    VMContext,

    /// Value is pointed to by another global value.
    ///
    /// The `base` global value is assumed to contain a pointer. This global value is computed
    /// by loading from memory at that pointer value. The memory must be accessible, and
    /// naturally aligned to hold a value of the type. The data at this address is assumed
    /// to never change while the current function is executing.
    Load {
        /// The base pointer global value.
        base: GlobalValue,

        /// Offset added to the base pointer before doing the load.
        offset: Offset32,

        /// Type of the loaded value.
        global_type: Type,

        /// Specifies whether the memory that this refers to is readonly, allowing for the
        /// elimination of redundant loads.
        readonly: bool,
    },

    /// Value is an offset from another global value.
    IAddImm {
        /// The base pointer global value.
        base: GlobalValue,

        /// Byte offset to be added to the value.
        offset: Imm64,

        /// Type of the iadd.
        global_type: Type,
    },

    /// Value is symbolic, meaning it's a name which will be resolved to an
    /// actual value later (eg. by linking). Cranelift itself does not interpret
    /// this name; it's used by embedders to link with other data structures.
    ///
    /// For now, symbolic values always have pointer type, and represent
    /// addresses, however in the future they could be used to represent other
    /// things as well.
    Symbol {
        /// The symbolic name.
        name: ExternalName,

        /// Offset from the symbol. This can be used instead of IAddImm to represent folding an
        /// offset into a symbol.
        offset: Imm64,

        /// Will this symbol be defined nearby, such that it will always be a certain distance
        /// away, after linking? If so, references to it can avoid going through a GOT. Note that
        /// symbols meant to be preemptible cannot be colocated.
        colocated: bool,
    },
}

impl GlobalValueData {
    /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
    pub fn symbol_name(&self) -> &ExternalName {
        match *self {
            GlobalValueData::Symbol { ref name, .. } => name,
            _ => panic!("only symbols have names"),
        }
    }

    /// Return the type of this global.
    pub fn global_type(&self, isa: &TargetIsa) -> Type {
        match *self {
            GlobalValueData::VMContext { .. } | GlobalValueData::Symbol { .. } => {
                isa.pointer_type()
            }
            GlobalValueData::IAddImm { global_type, .. }
            | GlobalValueData::Load { global_type, .. } => global_type,
        }
    }
}

impl fmt::Display for GlobalValueData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GlobalValueData::VMContext => write!(f, "vmctx"),
            GlobalValueData::Load {
                base,
                offset,
                global_type,
                readonly,
            } => write!(
                f,
                "load.{} notrap aligned {}{}{}",
                global_type,
                if readonly { "readonly " } else { "" },
                base,
                offset
            ),
            GlobalValueData::IAddImm {
                global_type,
                base,
                offset,
            } => write!(f, "iadd_imm.{} {}, {}", global_type, base, offset),
            GlobalValueData::Symbol {
                ref name,
                offset,
                colocated,
            } => {
                if colocated {
                    write!(f, "colocated ")?;
                }
                write!(f, "symbol {}", name)?;
                let offset_val: i64 = offset.into();
                if offset_val > 0 {
                    write!(f, "+")?;
                }
                if offset_val != 0 {
                    write!(f, "{}", offset)?;
                }
                Ok(())
            }
        }
    }
}
<commit_msg>Fix global value colocated printing<commit_after>//! Global values.

use crate::ir::immediates::{Imm64, Offset32};
use crate::ir::{ExternalName, GlobalValue, Type};
use crate::isa::TargetIsa;
use core::fmt;

/// Information about a global value declaration.
#[derive(Clone)]
pub enum GlobalValueData {
    /// Value is the address of the VM context struct.
    VMContext,

    /// Value is pointed to by another global value.
    ///
    /// The `base` global value is assumed to contain a pointer. This global value is computed
    /// by loading from memory at that pointer value. The memory must be accessible, and
    /// naturally aligned to hold a value of the type. The data at this address is assumed
    /// to never change while the current function is executing.
    Load {
        /// The base pointer global value.
        base: GlobalValue,

        /// Offset added to the base pointer before doing the load.
        offset: Offset32,

        /// Type of the loaded value.
        global_type: Type,

        /// Specifies whether the memory that this refers to is readonly, allowing for the
        /// elimination of redundant loads.
        readonly: bool,
    },

    /// Value is an offset from another global value.
    IAddImm {
        /// The base pointer global value.
        base: GlobalValue,

        /// Byte offset to be added to the value.
        offset: Imm64,

        /// Type of the iadd.
        global_type: Type,
    },

    /// Value is symbolic, meaning it's a name which will be resolved to an
    /// actual value later (eg. by linking). Cranelift itself does not interpret
    /// this name; it's used by embedders to link with other data structures.
    ///
    /// For now, symbolic values always have pointer type, and represent
    /// addresses, however in the future they could be used to represent other
    /// things as well.
    Symbol {
        /// The symbolic name.
        name: ExternalName,

        /// Offset from the symbol. This can be used instead of IAddImm to represent folding an
        /// offset into a symbol.
        offset: Imm64,

        /// Will this symbol be defined nearby, such that it will always be a certain distance
        /// away, after linking? If so, references to it can avoid going through a GOT. Note that
        /// symbols meant to be preemptible cannot be colocated.
        colocated: bool,
    },
}

impl GlobalValueData {
    /// Assume that `self` is an `GlobalValueData::Symbol` and return its name.
    pub fn symbol_name(&self) -> &ExternalName {
        match *self {
            GlobalValueData::Symbol { ref name, .. } => name,
            _ => panic!("only symbols have names"),
        }
    }

    /// Return the type of this global.
    pub fn global_type(&self, isa: &TargetIsa) -> Type {
        match *self {
            GlobalValueData::VMContext { .. } | GlobalValueData::Symbol { .. } => {
                isa.pointer_type()
            }
            GlobalValueData::IAddImm { global_type, .. }
            | GlobalValueData::Load { global_type, .. } => global_type,
        }
    }
}

impl fmt::Display for GlobalValueData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GlobalValueData::VMContext => write!(f, "vmctx"),
            GlobalValueData::Load {
                base,
                offset,
                global_type,
                readonly,
            } => write!(
                f,
                "load.{} notrap aligned {}{}{}",
                global_type,
                if readonly { "readonly " } else { "" },
                base,
                offset
            ),
            GlobalValueData::IAddImm {
                global_type,
                base,
                offset,
            } => write!(f, "iadd_imm.{} {}, {}", global_type, base, offset),
            GlobalValueData::Symbol {
                ref name,
                offset,
                colocated,
            } => {
                write!(
                    f,
                    "symbol {}{}",
                    if colocated { "colocated " } else { "" },
                    name
                )?;
                let offset_val: i64 = offset.into();
                if offset_val > 0 {
                    write!(f, "+")?;
                }
                if offset_val != 0 {
                    write!(f, "{}", offset)?;
                }
                Ok(())
            }
        }
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(rustfmt, rustfmt_skip)] // https://github.com/rust-lang-nursery/rustfmt/issues/2755

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_body {
    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = ReturnBasedOnArgs,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = ST,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (ST,),
            expression_bounds = ($($ty_param: $crate::expression::Expression<SqlType = ST>,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (),
            expression_bounds = ($($ty_param: $crate::expression::Expression,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = ($($field_name:ident,)+),
        backend_ty_params = ($($backend_ty_param:ident,)*),
        backend_ty = $backend_ty:ty,
        expression_ty_params = ($($expression_ty_params:ident,)*),
        expression_bounds = ($($expression_bounds:tt)*),
    ) => {
        #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, NonAggregate)]
        #[doc(hidden)]
        pub struct $name<$($ty_param,)+> {
            $(pub(crate) $field_name: $ty_param,)+
        }

        impl<$($ty_param,)+> $name<$($ty_param,)+> {
            pub fn new($($field_name: $ty_param,)+) -> Self {
                $name { $($field_name,)+ }
            }
        }

        impl_selectable_expression!($name<$($ty_param),+>);

        impl<$($ty_param,)+ $($expression_ty_params,)*> $crate::expression::Expression for $name<$($ty_param,)+> where
            $($expression_bounds)*
        {
            type SqlType = $return_ty;
        }

        impl<$($ty_param,)+ $($backend_ty_param,)*> $crate::query_builder::QueryFragment<$backend_ty>
            for $name<$($ty_param,)+> where
                $($ty_param: $crate::query_builder::QueryFragment<$backend_ty>,)+
                $($backend_ty_param: $crate::backend::Backend,)*
        {
            fn walk_ast(&self, mut out: $crate::query_builder::AstPass<$backend_ty>) -> $crate::result::QueryResult<()> {
                __diesel_operator_to_sql!(
                    notation = $notation,
                    operator_expr = out.push_sql($operator),
                    field_exprs = ($(self.$field_name.walk_ast(out.reborrow())?),+),
                );
                Ok(())
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_to_sql {
    (
        notation = infix,
        operator_expr = $op:expr,
        field_exprs = ($left:expr, $right:expr),
    ) => {
        $left;
        $op;
        $right;
    };

    (
        notation = postfix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $expr;
        $op;
    };

    (
        notation = prefix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $op;
        $expr;
    };
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// This will create a new type with the given name. It will implement all
/// methods needed to be used as an expression in Diesel, placing the given
/// SQL between the two elements. The third argument specifies the SQL type
/// that the operator returns. If it is not given, the type will be assumed
/// to be `Bool`.
///
/// If the operator is specific to a single backend, you can specify this by
/// adding `backend: Pg` or similar as the last argument.
///
/// It should be noted that the generated impls will not constrain the SQL
/// types of the arguments. You should ensure that they are of the right
/// type in your function which constructs the operator.
///
/// Typically you would not expose the type that this generates directly. You'd
/// expose a function (or trait) used to construct the expression, and a helper
/// type which represents the return type of that function. See the source of
/// `diesel::expression::expression_methods` and
/// `diesel::expression::helper_types` for real world examples of this.
///
/// # Examples
///
/// # Possible invocations
///
/// ```ignore
/// // The SQL type will be boolean. The backend will not be constrained
/// infix_operator!(Matches, " @@ ");
///
/// // Queries which try to execute `Contains` on a backend other than Pg
/// // will fail to compile
/// infix_operator!(Contains, " @> ", backend: Pg);
///
/// // The type of `Concat` will be `TsVector` rather than Bool
/// infix_operator!(Concat, " || ", TsVector);
///
/// // It is perfectly fine to have multiple operators with the same SQL.
/// // Diesel will ensure that the queries are always unambiguous in which
/// // operator applies
/// infix_operator!(Or, " || ", TsQuery);
///
/// // Specifying both the return types and the backend
/// infix_operator!(And, " && ", TsQuery, backend: Pg);
/// ```
///
/// ## Example usage
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// infix_operator!(MyEq, " = ");
///
/// use diesel::expression::AsExpression;
///
/// // Normally you would put this on a trait instead
/// fn my_eq<T, U>(left: T, right: U) -> MyEq<T, U::Expression> where
///     T: Expression,
///     U: AsExpression<T::SqlType>,
/// {
///     MyEq::new(left, right.as_expression())
/// }
///
/// let users_with_name = users.select(id).filter(my_eq(name, "Sean"));
///
/// assert_eq!(Ok(1), users_with_name.first(&connection));
/// # }
/// ```
#[macro_export]
macro_rules! infix_operator {
    ($name:ident, $operator:expr) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $($return_ty:tt)::*) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $($return_ty)::*,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::infix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_infix_operator {
    ($($args:tt)*) => {
        infix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed after
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! postfix_operator {
    ($name:ident, $operator:expr) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::postfix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_postfix_operator {
    ($($args:tt)*) => {
        postfix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed before
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! prefix_operator {
    ($name:ident, $operator:expr) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::prefix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_prefix_operator {
    ($($args:tt)*) => {
        prefix_operator!($($args)*);
    }
}

infix_operator!(Concat, " || ", ReturnBasedOnArgs);
infix_operator!(And, " AND ");
infix_operator!(Between, " BETWEEN ");
infix_operator!(Escape, " ESCAPE ");
infix_operator!(Eq, " = ");
infix_operator!(Gt, " > ");
infix_operator!(GtEq, " >= ");
infix_operator!(Like, " LIKE ");
infix_operator!(Lt, " < ");
infix_operator!(LtEq, " <= ");
infix_operator!(NotBetween, " NOT BETWEEN ");
infix_operator!(NotEq, " != ");
infix_operator!(NotLike, " NOT LIKE ");
infix_operator!(Or, " OR ");

postfix_operator!(IsNull, " IS NULL");
postfix_operator!(IsNotNull, " IS NOT NULL");
postfix_operator!(Asc, " ASC", ());
postfix_operator!(Desc, " DESC", ());

prefix_operator!(Not, "NOT ");

use insertable::{ColumnInsertValue, Insertable};
use query_builder::ValuesClause;
use query_source::Column;

impl<T, U> Insertable<T::Table> for Eq<T, U>
where
    T: Column,
{
    type Values = ValuesClause<ColumnInsertValue<T, U>, T::Table>;

    fn values(self) -> Self::Values {
        ValuesClause::new(ColumnInsertValue::Expression(self.left, self.right))
    }
}

impl<'a, T, Tab, U> Insertable<Tab> for &'a Eq<T, U>
where
    T: Copy,
    Eq<T, &'a U>: Insertable<Tab>,
{
    type Values = <Eq<T, &'a U> as Insertable<Tab>>::Values;

    fn values(self) -> Self::Values {
        Eq::new(self.left, &self.right).values()
    }
}
<commit_msg>Workaround a bug in mysql 8.0.17 while using the concat operator<commit_after>#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_body {
    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = ReturnBasedOnArgs,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = ST,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (ST,),
            expression_bounds = ($($ty_param: $crate::expression::Expression<SqlType = ST>,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = $field_names:tt,
        backend_ty_params = $backend_ty_params:tt,
        backend_ty = $backend_ty:ty,
    ) => {
        __diesel_operator_body! {
            notation = $notation,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = ($($ty_param,)+),
            field_names = $field_names,
            backend_ty_params = $backend_ty_params,
            backend_ty = $backend_ty,
            expression_ty_params = (),
            expression_bounds = ($($ty_param: $crate::expression::Expression,)+),
        }
    };

    (
        notation = $notation:ident,
        struct_name = $name:ident,
        operator = $operator:expr,
        return_ty = $return_ty:ty,
        ty_params = ($($ty_param:ident,)+),
        field_names = ($($field_name:ident,)+),
        backend_ty_params = ($($backend_ty_param:ident,)*),
        backend_ty = $backend_ty:ty,
        expression_ty_params = ($($expression_ty_params:ident,)*),
        expression_bounds = ($($expression_bounds:tt)*),
    ) => {
        #[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, NonAggregate)]
        #[doc(hidden)]
        pub struct $name<$($ty_param,)+> {
            $(pub(crate) $field_name: $ty_param,)+
        }

        impl<$($ty_param,)+> $name<$($ty_param,)+> {
            pub fn new($($field_name: $ty_param,)+) -> Self {
                $name { $($field_name,)+ }
            }
        }

        impl_selectable_expression!($name<$($ty_param),+>);

        impl<$($ty_param,)+ $($expression_ty_params,)*> $crate::expression::Expression for $name<$($ty_param,)+> where
            $($expression_bounds)*
        {
            type SqlType = $return_ty;
        }

        impl<$($ty_param,)+ $($backend_ty_param,)*> $crate::query_builder::QueryFragment<$backend_ty>
            for $name<$($ty_param,)+> where
                $($ty_param: $crate::query_builder::QueryFragment<$backend_ty>,)+
                $($backend_ty_param: $crate::backend::Backend,)*
        {
            fn walk_ast(&self, mut out: $crate::query_builder::AstPass<$backend_ty>) -> $crate::result::QueryResult<()> {
                __diesel_operator_to_sql!(
                    notation = $notation,
                    operator_expr = out.push_sql($operator),
                    field_exprs = ($(self.$field_name.walk_ast(out.reborrow())?),+),
                );
                Ok(())
            }
        }
    }
}

#[macro_export]
#[doc(hidden)]
macro_rules! __diesel_operator_to_sql {
    (
        notation = infix,
        operator_expr = $op:expr,
        field_exprs = ($left:expr, $right:expr),
    ) => {
        $left;
        $op;
        $right;
    };

    (
        notation = postfix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $expr;
        $op;
    };

    (
        notation = prefix,
        operator_expr = $op:expr,
        field_exprs = ($expr:expr),
    ) => {
        $op;
        $expr;
    };
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// This will create a new type with the given name. It will implement all
/// methods needed to be used as an expression in Diesel, placing the given
/// SQL between the two elements. The third argument specifies the SQL type
/// that the operator returns. If it is not given, the type will be assumed
/// to be `Bool`.
///
/// If the operator is specific to a single backend, you can specify this by
/// adding `backend: Pg` or similar as the last argument.
///
/// It should be noted that the generated impls will not constrain the SQL
/// types of the arguments. You should ensure that they are of the right
/// type in your function which constructs the operator.
///
/// Typically you would not expose the type that this generates directly. You'd
/// expose a function (or trait) used to construct the expression, and a helper
/// type which represents the return type of that function. See the source of
/// `diesel::expression::expression_methods` and
/// `diesel::expression::helper_types` for real world examples of this.
///
/// # Examples
///
/// # Possible invocations
///
/// ```ignore
/// // The SQL type will be boolean. The backend will not be constrained
/// infix_operator!(Matches, " @@ ");
///
/// // Queries which try to execute `Contains` on a backend other than Pg
/// // will fail to compile
/// infix_operator!(Contains, " @> ", backend: Pg);
///
/// // The type of `Concat` will be `TsVector` rather than Bool
/// infix_operator!(Concat, " || ", TsVector);
///
/// // It is perfectly fine to have multiple operators with the same SQL.
/// // Diesel will ensure that the queries are always unambiguous in which
/// // operator applies
/// infix_operator!(Or, " || ", TsQuery);
///
/// // Specifying both the return types and the backend
/// infix_operator!(And, " && ", TsQuery, backend: Pg);
/// ```
///
/// ## Example usage
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// infix_operator!(MyEq, " = ");
///
/// use diesel::expression::AsExpression;
///
/// // Normally you would put this on a trait instead
/// fn my_eq<T, U>(left: T, right: U) -> MyEq<T, U::Expression> where
///     T: Expression,
///     U: AsExpression<T::SqlType>,
/// {
///     MyEq::new(left, right.as_expression())
/// }
///
/// let users_with_name = users.select(id).filter(my_eq(name, "Sean"));
///
/// assert_eq!(Ok(1), users_with_name.first(&connection));
/// # }
/// ```
#[macro_export]
macro_rules! infix_operator {
    ($name:ident, $operator:expr) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        infix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $($return_ty:tt)::*) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $($return_ty)::*,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = infix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (T, U,),
            field_names = (left, right,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::infix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_infix_operator {
    ($($args:tt)*) => {
        infix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed after
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! postfix_operator {
    ($name:ident, $operator:expr) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        postfix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = postfix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::postfix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_postfix_operator {
    ($($args:tt)*) => {
        postfix_operator!($($args)*);
    }
}

/// Useful for libraries adding support for new SQL types. Apps should never
/// need to call this.
///
/// Similar to [`infix_operator!`], but the generated type will only take
/// a single argument rather than two. The operator SQL will be placed before
/// the single argument. See [`infix_operator!`] for example usage.
///
/// [`infix_operator!`]: macro.infix_operator.html
#[macro_export]
macro_rules! prefix_operator {
    ($name:ident, $operator:expr) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool);
    };

    ($name:ident, $operator:expr, backend: $backend:ty) => {
        prefix_operator!($name, $operator, $crate::sql_types::Bool, backend: $backend);
    };

    ($name:ident, $operator:expr, $return_ty:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (DB,),
            backend_ty = DB,
        );
    };

    ($name:ident, $operator:expr, $return_ty:ty, backend: $backend:ty) => {
        __diesel_operator_body!(
            notation = prefix,
            struct_name = $name,
            operator = $operator,
            return_ty = $return_ty,
            ty_params = (Expr,),
            field_names = (expr,),
            backend_ty_params = (),
            backend_ty = $backend,
        );
    };
}

#[macro_export]
#[deprecated(since = "2.0.0", note = "use `diesel::prefix_operator!` instead")]
#[cfg(feature = "with-deprecated")]
#[doc(hidden)]
macro_rules! diesel_prefix_operator {
    ($($args:tt)*) => {
        prefix_operator!($($args)*);
    }
}

infix_operator!(And, " AND ");
infix_operator!(Between, " BETWEEN ");
infix_operator!(Escape, " ESCAPE ");
infix_operator!(Eq, " = ");
infix_operator!(Gt, " > ");
infix_operator!(GtEq, " >= ");
infix_operator!(Like, " LIKE ");
infix_operator!(Lt, " < ");
infix_operator!(LtEq, " <= ");
infix_operator!(NotBetween, " NOT BETWEEN ");
infix_operator!(NotEq, " != ");
infix_operator!(NotLike, " NOT LIKE ");
infix_operator!(Or, " OR ");

postfix_operator!(IsNull, " IS NULL");
postfix_operator!(IsNotNull, " IS NOT NULL");
postfix_operator!(Asc, " ASC", ());
postfix_operator!(Desc, " DESC", ());

prefix_operator!(Not, "NOT ");

use insertable::{ColumnInsertValue, Insertable};
use query_builder::ValuesClause;
use query_source::Column;

impl<T, U> Insertable<T::Table> for Eq<T, U>
where
    T: Column,
{
    type Values = ValuesClause<ColumnInsertValue<T, U>, T::Table>;

    fn values(self) -> Self::Values {
        ValuesClause::new(ColumnInsertValue::Expression(self.left, self.right))
    }
}

impl<'a, T, Tab, U> Insertable<Tab> for &'a Eq<T, U>
where
    T: Copy,
    Eq<T, &'a U>: Insertable<Tab>,
{
    type Values = <Eq<T, &'a U> as Insertable<Tab>>::Values;

    fn values(self) -> Self::Values {
        Eq::new(self.left, &self.right).values()
    }
}

#[derive(Debug, Clone, Copy, QueryId, DieselNumericOps, NonAggregate)]
#[doc(hidden)]
pub struct Concat<L, R> {
    pub(crate) left: L,
    pub(crate) right: R,
}

impl<L, R> Concat<L, R> {
    pub fn new(left: L, right: R) -> Self {
        Self { left, right }
    }
}

impl<L, R, ST> ::expression::Expression for Concat<L, R>
where
    L: ::expression::Expression<SqlType = ST>,
    R: ::expression::Expression<SqlType = ST>,
{
    type SqlType = ST;
}

impl_selectable_expression!(Concat<L, R>);

impl<L, R, DB> ::query_builder::QueryFragment<DB> for Concat<L, R>
where
    L: ::query_builder::QueryFragment<DB>,
    R: ::query_builder::QueryFragment<DB>,
    DB: ::backend::Backend,
{
    fn walk_ast(&self, mut out: ::query_builder::AstPass<DB>) -> ::result::QueryResult<()> {
        // Those brackets are required because mysql is broken
        // https://github.com/diesel-rs/diesel/issues/2133#issuecomment-517432317
        out.push_sql("(");
        self.left.walk_ast(out.reborrow())?;
        out.push_sql(" || ");
        self.right.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate getopts;
extern crate locomix;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use self::byteorder::{NativeEndian, ReadBytesExt};
use getopts::Options;
use locomix::alsa_input;
use locomix::async_input;
use locomix::base;
use locomix::brutefir;
use locomix::control;
use locomix::filters;
use locomix::input;
use locomix::light;
use locomix::mixer;
use locomix::output;
use locomix::pipe_input;
use locomix::state_script;
use locomix::time::TimeDelta;
use locomix::ui;
use locomix::web_ui;
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::io;
use std::io::Read;

struct RunError {
    msg: String,
}

impl RunError {
    pub fn new(msg: &str) -> RunError {
        RunError {
            msg: String::from(msg),
        }
    }
}

impl From<io::Error> for RunError {
    fn from(e: io::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<toml::de::Error> for RunError {
    fn from(e: toml::de::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<getopts::Fail> for RunError {
    fn from(e: getopts::Fail) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<base::Error> for RunError {
    fn from(e: base::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

#[derive(Deserialize)]
struct InputConfig {
    name: Option<String>,
    #[serde(rename = "type")]
    type_: Option<String>,
    device: String,
    sample_rate: Option<usize>,
    channel_map: Option<String>,
    default_gain: Option<f32>,
    enable_a52: Option<bool>,

    // Enables sample rate probing. Useful for sound cards that don't
    // detect input rate, e.g. Creative SB X-Fi HD.
    probe_sample_rate: Option<bool>,
}

#[derive(Deserialize)]
struct CompositeOutputEntry {
    device: String,
    sample_rate: Option<usize>,
    channel_map: Option<String>,
    delay: Option<f64>,
}

#[derive(Deserialize)]
struct OutputConfig {
    name: Option<String>,
    device: Option<String>,
    devices: Option<Vec<CompositeOutputEntry>>,
    channel_map: Option<String>,
    sample_rate: Option<usize>,
    default_gain: Option<f32>,
    subwoofer_crossover_frequency: Option<usize>,
    fir_filters: Option<BTreeMap<String, String>>,
    fir_length: Option<usize>,
    use_brutefir: Option<bool>,
}

#[derive(Deserialize)]
struct ControlDeviceConfig {
    #[serde(rename = "type")]
    type_: String,
    device: String,
}

#[derive(Deserialize)]
struct Config {
    sample_rate: Option<usize>,
    web_address: Option<String>,
    period_duration: Option<usize>,
    state_script: Option<String>,
    enable_crossfeed: Option<bool>,
    resampler_window: Option<usize>,

    input: Vec<InputConfig>,
    output: Vec<OutputConfig>,
    control_device: Option<Vec<ControlDeviceConfig>>,
}

fn parse_channel_id(id: String) -> Result<base::ChannelPos, RunError> {
    match id.to_uppercase().as_str() {
        "L" | "FL" | "LEFT" => Ok(base::ChannelPos::FL),
        "R" | "FR" | "RIGHT" => Ok(base::ChannelPos::FR),
        "C" | "FC" | "CENTER" | "CENTRE" => Ok(base::ChannelPos::FC),
        "SL" | "SURROUND_LEFT" => Ok(base::ChannelPos::SL),
        "SR" | "SURROUND_RIGHT" => Ok(base::ChannelPos::SR),
        "SC" | "SURROUND" | "SURROUND_CENTER" | "SURROUND_CENTRE" => Ok(base::ChannelPos::SC),
        "S" | "B" | "SUB" | "LFE" => Ok(base::ChannelPos::Sub),
        "_" => Ok(base::ChannelPos::Other),
        _ => Err(RunError::new(
            format!("Invalid channel id: {}", id).as_str(),
        )),
    }
}

fn parse_channel_map(map_str: Option<String>) -> Result<Vec<base::ChannelPos>, RunError> {
    let unwrapped = map_str.unwrap_or("L R".to_string());
    let names: Vec<String> = unwrapped
        .as_str()
        .split_whitespace()
        .map(|s| s.to_string())
        .collect();
    let mut result: Vec<base::ChannelPos> = vec![];
    for n in names {
        result.push(parse_channel_id(n)?);
    }

    if result.len() < 2 {
        return Err(RunError::new(
            format!("Invalid channel map: {}", unwrapped).as_str(),
        ));
    }

    Ok(result)
}

fn load_fir_params(filename: &str, size: usize) -> Result<filters::FirFilterParams, RunError> {
    let mut file = try!(fs::File::open(filename));
    let mut result = Vec::<f32>::new();
    loop {
        match file.read_f32::<NativeEndian>() {
            Ok(value) => result.push(value),
            Err(_) => break,
        }
    }
    Ok(filters::FirFilterParams::new(result, size))
}

fn load_fir_set(
    files: Option<BTreeMap<String, String>>,
    length: usize,
    sample_rate: usize,
    period_duration: TimeDelta,
    use_brutefir: bool,
) -> Result<Option<Box<filters::StreamFilter>>, RunError> {
    let mut filters = base::PerChannel::new();
    match files {
        None => return Ok(None),
        Some(map) => for (c, f) in map {
            filters.set(parse_channel_id(c)?, f)
        },
    }

    if use_brutefir {
        Ok(Some(Box::new(brutefir::BruteFir::new(
            filters,
            sample_rate,
            period_duration,
            length,
        )?)))
    } else {
        let mut loaded = base::PerChannel::new();
        for (c, f) in filters.iter() {
            loaded.set(c, load_fir_params(&f, length)?);
        }
        Ok(Some(Box::new(filters::MultichannelFirFilter::new(loaded))))
    }
}

fn run() -> Result<(), RunError> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optmulti("c", "config", "Config file", "CONFIG_FILE");
    opts.optflag("h", "help", "Print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    if matches.opt_present("h") {
        print!("Usage: {} --config <CONFIG_FILE>\n", args[0]);
        return Ok(());
    }

    let config_filename = match matches.opt_str("c") {
        None => return Err(RunError::new("--config is not specified.")),
        Some(c) => c,
    };

    let mut file = try!(fs::File::open(config_filename));
    let mut config_content = String::new();
    try!(file.read_to_string(&mut config_content));

    let config: Config = try!(toml::from_str(config_content.as_str()));

    let sample_rate = config.sample_rate.unwrap_or(48000);
    if sample_rate < 8000 || sample_rate > 192000 {
        return Err(RunError::new(
            format!("Invalid sample_rate: {}", sample_rate).as_str(),
        ));
    }

    let period_duration = TimeDelta::milliseconds(config.period_duration.unwrap_or(100) as i64);
    if period_duration < TimeDelta::milliseconds(1) || period_duration > TimeDelta::seconds(1) {
        return Err(RunError::new(
            format!(
                "Invalid period_duration: {}",
                config.period_duration.unwrap()
            ).as_str(),
        ));
    }

    let resampler_window = config.resampler_window.unwrap_or(24);
    if resampler_window < 2 || resampler_window > 2000 {
        return Err(RunError::new(
            format!("Invalid resampler_window: {}", resampler_window).as_str(),
        ));
    }

    let shared_state = ui::SharedState::new();

    let mut inputs = Vec::<async_input::AsyncInput>::new();
    for input in config.input {
        let name = input.name.unwrap_or(input.device.clone());
        let default_gain = input.default_gain.unwrap_or(0.0);
        shared_state.lock().add_input(ui::InputState {
            name: name.clone(),
            gain: base::Gain { db: default_gain },
        });

        let type_ = input.type_.unwrap_or("alsa".to_string());
        let spec = base::DeviceSpec {
            name: name,
            id: input.device,
            sample_rate: input.sample_rate,
            channels: parse_channel_map(input.channel_map)?,
            delay: TimeDelta::zero(),
            enable_a52: input.enable_a52.unwrap_or(false),
        };
        let device: Box<input::Input> = match type_.as_str() {
            "pipe" => pipe_input::PipeInput::open(spec, period_duration),
            "alsa" => alsa_input::ResilientAlsaInput::new(
                spec,
                period_duration,
                input.probe_sample_rate.unwrap_or(false),
            ),
            _ => {
                return Err(RunError::new(
                    format!("Unknown input type: {}", type_).as_str(),
                ))
            }
        };

        let async_resampled = async_input::AsyncInput::new(Box::new(input::InputResampler::new(
            device,
            sample_rate as f64,
            resampler_window,
        )));

        inputs.push(async_resampled);
    }

    if inputs.is_empty() {
        return Err(RunError::new("No inputs specified."));
    }

    let mut outputs = Vec::<Box<output::Output>>::new();
    let mut index = 0;
    for output in config.output {
        index += 1;
        let name = output.name.unwrap_or(format!("Output {}", index));

        let devices = match (output.device, output.channel_map, output.devices) {
            (Some(device), channel_map, None) => vec![base::DeviceSpec {
                name: name.clone(),
                id: device,
                sample_rate: output.sample_rate,
                channels: try!(parse_channel_map(channel_map)),
                delay: TimeDelta::zero(),
                enable_a52: false,
            }],
            (None, None, Some(devices)) => {
                let mut result = vec![];
                for d in devices {
                    result.push(base::DeviceSpec {
                        name: "".to_string(),
                        id: d.device,
                        sample_rate: d.sample_rate.or(output.sample_rate),
                        channels: try!(parse_channel_map(d.channel_map)),
                        delay: TimeDelta::milliseconds_f(d.delay.unwrap_or(0f64)),
                        enable_a52: false,
                    });
                }
                result
            }
            (Some(_), _, Some(_)) => {
                return Err(RunError::new(
                    "device and devices fields cannot be specified together.",
                ));
            }
            (_, Some(_), Some(_)) => {
                return Err(RunError::new(
                    "channel_map cannot be specified for a composite output device.",
                ));
            }
            (None, _, None) => {
                return Err(RunError::new(
                    "Either device or devices must be specified for each output.",
                ));
            }
        };

        let mut channels = base::PerChannel::new();
        for d in devices.iter() {
            for c in d.channels.iter() {
                if *c != base::ChannelPos::Other {
                    channels.set(*c, true);
                }
            }
        }

        let have_subwoofer = channels.get(base::ChannelPos::Sub) == Some(&true);

        let out = try!(output::CompositeOutput::new(
            devices,
            period_duration,
            resampler_window,
        ));

        let sub_config = match (have_subwoofer, output.subwoofer_crossover_frequency) {
            (false, Some(_)) => {
                return Err(RunError::new(
                    format!(
                "subwoofer_crossover_frequency is set for output {}, which doesn't have subwoofer.",
                name
            ).as_str(),
                ))
            }
            (false, None) => None,
            (true, None) => Some(ui::SubwooferConfig {
                crossover_frequency: 80.0,
            }),
            (true, Some(f)) if f > 20 && f < 1000 => Some(ui::SubwooferConfig {
                crossover_frequency: 80.0,
            }),
            (true, Some(f)) => {
                return Err(RunError::new(
                    format!("Invalid subwoofer_crossover_frequency: {}", f).as_str(),
                ))
            }
        };

        let fir_length = output.fir_length.unwrap_or(5000);
        let use_brutefir = output.use_brutefir.unwrap_or(false);
        let fir_filters = load_fir_set(
            output.fir_filters,
            fir_length,
            sample_rate,
            period_duration,
            use_brutefir,
        )?;

        let default_gain = output
            .default_gain
            .unwrap_or((ui::VOLUME_MIN + ui::VOLUME_MAX) / 2.0);
        shared_state.lock().add_output(ui::OutputState {
            name: name.clone(),
            gain: base::Gain { db: default_gain },
            drc_supported: fir_filters.is_some(),
            subwoofer: sub_config,
        });

        let out = output::AsyncOutput::new(mixer::FilteredOutput::new(
            out,
            channels,
            fir_filters,
            sub_config,
            &shared_state,
        ));

        outputs.push(out);
    }

    if config.control_device.is_some() {
        for device in config.control_device.unwrap() {
            match device.type_.as_str() {
                "input" => {
                    control::start_input_handler(&device.device, shared_state.clone());
                }
                "griffin_powermate" => {
                    control::start_input_handler(&device.device, shared_state.clone());
                    light::start_light_controller(&device.device, shared_state.clone());
                }
                c => {
                    println!("WARNING: Unrecognized control device type {}", c);
                }
            }
        }
    }

    let web_addr = config.web_address.unwrap_or("0.0.0.0:8000".to_string());
    web_ui::start_web(&web_addr, shared_state.clone());

    match config.state_script {
        Some(s) => state_script::start_state_script_contoller(&s, shared_state.clone()),
        None => (),
    }

    if config.enable_crossfeed.unwrap_or(false) {
        shared_state
            .lock()
            .set_crossfeed(ui::CrossfeedConfig::default());
    }

    Ok(try!(mixer::run_mixer_loop(
        inputs,
        outputs,
        sample_rate as f64,
        period_duration,
        shared_state,
    )))
}

fn main() {
    match run() {
        Err(e) => {
            println!("{}", e.msg);
            std::process::exit(-1);
        }
        Ok(_) => (),
    }
}
<commit_msg>Use system alloc<commit_after>#![feature(allocator_api)]

extern crate byteorder;
extern crate getopts;
extern crate locomix;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use self::byteorder::{NativeEndian, ReadBytesExt};
use getopts::Options;
use locomix::alsa_input;
use locomix::async_input;
use locomix::base;
use locomix::brutefir;
use locomix::control;
use locomix::filters;
use locomix::input;
use locomix::light;
use locomix::mixer;
use locomix::output;
use locomix::pipe_input;
use locomix::state_script;
use locomix::time::TimeDelta;
use locomix::ui;
use locomix::web_ui;
use std::alloc::System;
use std::collections::BTreeMap;
use std::env;
use std::fs;
use std::io;
use std::io::Read;

#[global_allocator]
static ALLOCATOR: System = System;

struct RunError {
    msg: String,
}

impl RunError {
    pub fn new(msg: &str) -> RunError {
        RunError {
            msg: String::from(msg),
        }
    }
}

impl From<io::Error> for RunError {
    fn from(e: io::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<toml::de::Error> for RunError {
    fn from(e: toml::de::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<getopts::Fail> for RunError {
    fn from(e: getopts::Fail) -> RunError {
        RunError { msg: e.to_string() }
    }
}

impl From<base::Error> for RunError {
    fn from(e: base::Error) -> RunError {
        RunError { msg: e.to_string() }
    }
}

#[derive(Deserialize)]
struct InputConfig {
    name: Option<String>,
    #[serde(rename = "type")]
    type_: Option<String>,
    device: String,
    sample_rate: Option<usize>,
    channel_map: Option<String>,
    default_gain: Option<f32>,
    enable_a52: Option<bool>,

    // Enables sample rate probing. Useful for sound cards that don't
    // detect input rate, e.g. Creative SB X-Fi HD.
    probe_sample_rate: Option<bool>,
}

#[derive(Deserialize)]
struct CompositeOutputEntry {
    device: String,
    sample_rate: Option<usize>,
    channel_map: Option<String>,
    delay: Option<f64>,
}

#[derive(Deserialize)]
struct OutputConfig {
    name: Option<String>,
    device: Option<String>,
    devices: Option<Vec<CompositeOutputEntry>>,
    channel_map: Option<String>,
    sample_rate: Option<usize>,
    default_gain: Option<f32>,
    subwoofer_crossover_frequency: Option<usize>,
    fir_filters: Option<BTreeMap<String, String>>,
    fir_length: Option<usize>,
    use_brutefir: Option<bool>,
}

#[derive(Deserialize)]
struct ControlDeviceConfig {
    #[serde(rename = "type")]
    type_: String,
    device: String,
}

#[derive(Deserialize)]
struct Config {
    sample_rate: Option<usize>,
    web_address: Option<String>,
    period_duration: Option<usize>,
    state_script: Option<String>,
    enable_crossfeed: Option<bool>,
    resampler_window: Option<usize>,

    input: Vec<InputConfig>,
    output: Vec<OutputConfig>,
    control_device: Option<Vec<ControlDeviceConfig>>,
}

fn parse_channel_id(id: String) -> Result<base::ChannelPos, RunError> {
    match id.to_uppercase().as_str() {
        "L" | "FL" | "LEFT" => Ok(base::ChannelPos::FL),
        "R" | "FR" | "RIGHT" => Ok(base::ChannelPos::FR),
        "C" | "FC" | "CENTER" | "CENTRE" => Ok(base::ChannelPos::FC),
        "SL" | "SURROUND_LEFT" => Ok(base::ChannelPos::SL),
        "SR" | "SURROUND_RIGHT" => Ok(base::ChannelPos::SR),
        "SC" | "SURROUND" | "SURROUND_CENTER" | "SURROUND_CENTRE" => Ok(base::ChannelPos::SC),
        "S" | "B" | "SUB" | "LFE" => Ok(base::ChannelPos::Sub),
        "_" => Ok(base::ChannelPos::Other),
        _ => Err(RunError::new(
            format!("Invalid channel id: {}", id).as_str(),
        )),
    }
}

fn parse_channel_map(map_str: Option<String>) -> Result<Vec<base::ChannelPos>, RunError> {
    let unwrapped = map_str.unwrap_or("L R".to_string());
    let names: Vec<String> = unwrapped
        .as_str()
        .split_whitespace()
        .map(|s| s.to_string())
        .collect();
    let mut result: Vec<base::ChannelPos> = vec![];
    for n in names {
        result.push(parse_channel_id(n)?);
    }

    if result.len() < 2 {
        return Err(RunError::new(
            format!("Invalid channel map: {}", unwrapped).as_str(),
        ));
    }

    Ok(result)
}

fn load_fir_params(filename: &str, size: usize) -> Result<filters::FirFilterParams, RunError> {
    let mut file = try!(fs::File::open(filename));
    let mut result = Vec::<f32>::new();
    loop {
        match file.read_f32::<NativeEndian>() {
            Ok(value) => result.push(value),
            Err(_) => break,
        }
    }
    Ok(filters::FirFilterParams::new(result, size))
}

fn load_fir_set(
    files: Option<BTreeMap<String, String>>,
    length: usize,
    sample_rate: usize,
    period_duration: TimeDelta,
    use_brutefir: bool,
) -> Result<Option<Box<filters::StreamFilter>>, RunError> {
    let mut filters = base::PerChannel::new();
    match files {
        None => return Ok(None),
        Some(map) => for (c, f) in map {
            filters.set(parse_channel_id(c)?, f)
        },
    }

    if use_brutefir {
        Ok(Some(Box::new(brutefir::BruteFir::new(
            filters,
            sample_rate,
            period_duration,
            length,
        )?)))
    } else {
        let mut loaded = base::PerChannel::new();
        for (c, f) in filters.iter() {
            loaded.set(c, load_fir_params(&f, length)?);
        }
        Ok(Some(Box::new(filters::MultichannelFirFilter::new(loaded))))
    }
}

fn run() -> Result<(), RunError> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optmulti("c", "config", "Config file", "CONFIG_FILE");
    opts.optflag("h", "help", "Print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    if matches.opt_present("h") {
        print!("Usage: {} --config <CONFIG_FILE>\n", args[0]);
        return Ok(());
    }

    let config_filename = match matches.opt_str("c") {
        None => return Err(RunError::new("--config is not specified.")),
        Some(c) => c,
    };

    let mut file = try!(fs::File::open(config_filename));
    let mut config_content = String::new();
    try!(file.read_to_string(&mut config_content));

    let config: Config = try!(toml::from_str(config_content.as_str()));

    let sample_rate = config.sample_rate.unwrap_or(48000);
    if sample_rate < 8000 || sample_rate > 192000 {
        return Err(RunError::new(
            format!("Invalid sample_rate: {}", sample_rate).as_str(),
        ));
    }

    let period_duration = TimeDelta::milliseconds(config.period_duration.unwrap_or(100) as i64);
    if period_duration < TimeDelta::milliseconds(1) || period_duration > TimeDelta::seconds(1) {
        return Err(RunError::new(
            format!(
                "Invalid period_duration: {}",
                config.period_duration.unwrap()
            ).as_str(),
        ));
    }

    let resampler_window = config.resampler_window.unwrap_or(24);
    if resampler_window < 2 || resampler_window > 2000 {
        return Err(RunError::new(
            format!("Invalid resampler_window: {}", resampler_window).as_str(),
        ));
    }

    let shared_state = ui::SharedState::new();

    let mut inputs = Vec::<async_input::AsyncInput>::new();
    for input in config.input {
        let name = input.name.unwrap_or(input.device.clone());
        let default_gain = input.default_gain.unwrap_or(0.0);
        shared_state.lock().add_input(ui::InputState {
            name: name.clone(),
            gain: base::Gain { db: default_gain },
        });

        let type_ = input.type_.unwrap_or("alsa".to_string());
        let spec = base::DeviceSpec {
            name: name,
            id: input.device,
            sample_rate: input.sample_rate,
            channels: parse_channel_map(input.channel_map)?,
            delay: TimeDelta::zero(),
            enable_a52: input.enable_a52.unwrap_or(false),
        };
        let device: Box<input::Input> = match type_.as_str() {
            "pipe" => pipe_input::PipeInput::open(spec, period_duration),
            "alsa" => alsa_input::ResilientAlsaInput::new(
                spec,
                period_duration,
                input.probe_sample_rate.unwrap_or(false),
            ),
            _ => {
                return Err(RunError::new(
                    format!("Unknown input type: {}", type_).as_str(),
                ))
            }
        };

        let async_resampled = async_input::AsyncInput::new(Box::new(input::InputResampler::new(
            device,
            sample_rate as f64,
            resampler_window,
        )));

        inputs.push(async_resampled);
    }

    if inputs.is_empty() {
        return Err(RunError::new("No inputs specified."));
    }

    let mut outputs = Vec::<Box<output::Output>>::new();
    let mut index = 0;
    for output in config.output {
        index += 1;
        let name = output.name.unwrap_or(format!("Output {}", index));

        let devices = match (output.device, output.channel_map, output.devices) {
            (Some(device), channel_map, None) => vec![base::DeviceSpec {
                name: name.clone(),
                id: device,
                sample_rate: output.sample_rate,
                channels: try!(parse_channel_map(channel_map)),
                delay: TimeDelta::zero(),
                enable_a52: false,
            }],
            (None, None, Some(devices)) => {
                let mut result = vec![];
                for d in devices {
                    result.push(base::DeviceSpec {
                        name: "".to_string(),
                        id: d.device,
                        sample_rate: d.sample_rate.or(output.sample_rate),
                        channels: try!(parse_channel_map(d.channel_map)),
                        delay: TimeDelta::milliseconds_f(d.delay.unwrap_or(0f64)),
                        enable_a52: false,
                    });
                }
                result
            }
            (Some(_), _, Some(_)) => {
                return Err(RunError::new(
                    "device and devices fields cannot be specified together.",
                ));
            }
            (_, Some(_), Some(_)) => {
                return Err(RunError::new(
                    "channel_map cannot be specified for a composite output device.",
                ));
            }
            (None, _, None) => {
                return Err(RunError::new(
                    "Either device or devices must be specified for each output.",
                ));
            }
        };

        let mut channels = base::PerChannel::new();
        for d in devices.iter() {
            for c in d.channels.iter() {
                if *c != base::ChannelPos::Other {
                    channels.set(*c, true);
                }
            }
        }

        let have_subwoofer = channels.get(base::ChannelPos::Sub) == Some(&true);

        let out = try!(output::CompositeOutput::new(
            devices,
            period_duration,
            resampler_window,
        ));

        let sub_config = match (have_subwoofer, output.subwoofer_crossover_frequency) {
            (false, Some(_)) => {
                return Err(RunError::new(
                    format!(
                "subwoofer_crossover_frequency is set for output {}, which doesn't have subwoofer.",
                name
            ).as_str(),
                ))
            }
            (false, None) => None,
            (true, None) => Some(ui::SubwooferConfig {
                crossover_frequency: 80.0,
            }),
            (true, Some(f)) if f > 20 && f < 1000 => Some(ui::SubwooferConfig {
                crossover_frequency: 80.0,
            }),
            (true, Some(f)) => {
                return Err(RunError::new(
                    format!("Invalid subwoofer_crossover_frequency: {}", f).as_str(),
                ))
            }
        };

        let fir_length = output.fir_length.unwrap_or(5000);
        let use_brutefir = output.use_brutefir.unwrap_or(false);
        let fir_filters = load_fir_set(
            output.fir_filters,
            fir_length,
            sample_rate,
            period_duration,
            use_brutefir,
        )?;

        let default_gain = output
            .default_gain
            .unwrap_or((ui::VOLUME_MIN + ui::VOLUME_MAX) / 2.0);
        shared_state.lock().add_output(ui::OutputState {
            name: name.clone(),
            gain: base::Gain { db: default_gain },
            drc_supported: fir_filters.is_some(),
            subwoofer: sub_config,
        });

        let out = output::AsyncOutput::new(mixer::FilteredOutput::new(
            out,
            channels,
            fir_filters,
            sub_config,
            &shared_state,
        ));

        outputs.push(out);
    }

    if config.control_device.is_some() {
        for device in config.control_device.unwrap() {
            match device.type_.as_str() {
                "input" => {
                    control::start_input_handler(&device.device, shared_state.clone());
                }
                "griffin_powermate" => {
                    control::start_input_handler(&device.device, shared_state.clone());
                    light::start_light_controller(&device.device, shared_state.clone());
                }
                c => {
                    println!("WARNING: Unrecognized control device type {}", c);
                }
            }
        }
    }

    let web_addr = config.web_address.unwrap_or("0.0.0.0:8000".to_string());
    web_ui::start_web(&web_addr, shared_state.clone());

    match config.state_script {
        Some(s) => state_script::start_state_script_contoller(&s, shared_state.clone()),
        None => (),
    }

    if config.enable_crossfeed.unwrap_or(false) {
        shared_state
            .lock()
            .set_crossfeed(ui::CrossfeedConfig::default());
    }

    Ok(try!(mixer::run_mixer_loop(
        inputs,
        outputs,
        sample_rate as f64,
        period_duration,
        shared_state,
    )))
}

fn main() {
    match run() {
        Err(e) => {
            println!("{}", e.msg);
            std::process::exit(-1);
        }
        Ok(_) => (),
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    /// The generated legend map.
    pub legend: BTreeMap<char, T>,
    /// Set to true if an add operation failed to assign a symbol.
    pub out_of_alphabet: bool,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
where
    T: Ord + Eq + Clone,
    F: FnMut(&T) -> &'static str,
{
    /// Initialize the legend builder.
    pub fn new(alphabet: String, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            out_of_alphabet: false,
            seen_values: BTreeMap::new(),
            prefix_fn,
            alphabet,
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        self.out_of_alphabet = true;
        Err(())
    }
}
<commit_msg>Better legend builder API<commit_after>use std::collections::BTreeMap;

/// Build a text map legend given an alphabet and a sequence of elements.
///
/// Each unique element will be assigned a letter from the alphabet. A preference function can
/// provide an additional alphabet prefix for specific values, which will be sampled before the
/// main alphabet. This will allow having standard special characters for eg. certain types of
/// terrain tiles. When no special alphabet is required, the preference function can return an
/// empty string.
pub struct LegendBuilder<T, F> {
    /// The generated legend map.
    pub legend: BTreeMap<char, T>,
    /// Set to true if an add operation failed to assign a symbol.
    pub out_of_alphabet: bool,
    seen_values: BTreeMap<T, char>,
    prefix_fn: F,
    alphabet: String,
}

impl<T, F> LegendBuilder<T, F>
where
    T: Ord + Eq + Clone,
    F: FnMut(&T) -> &'static str,
{
    /// Initialize the legend builder.
    pub fn new(alphabet: impl Into<String>, prefix_fn: F) -> LegendBuilder<T, F> {
        LegendBuilder {
            legend: BTreeMap::new(),
            out_of_alphabet: false,
            seen_values: BTreeMap::new(),
            prefix_fn,
            alphabet: alphabet.into(),
        }
    }

    /// Show a value to `LegendBuilder` and get its legend key.
    ///
    /// Returns an error if the alphabet has been exhausted.
    pub fn add(&mut self, value: &T) -> Result<char, ()> {
        if let Some(&c) = self.seen_values.get(value) {
            return Ok(c);
        }

        for c in (self.prefix_fn)(value).chars().chain(self.alphabet.chars()) {
            if self.legend.contains_key(&c) {
                continue;
            }

            self.legend.insert(c, value.clone());
            self.seen_values.insert(value.clone(), c);
            return Ok(c);
        }
        self.out_of_alphabet = true;
        Err(())
    }
}
<|endoftext|>


<commit_before>use super::settings::Settings;
use log::LevelFilter;
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use std::str::FromStr;
use std::sync::{Once, ONCE_INIT};

static INIT: Once = ONCE_INIT;

#[cfg(target_os = "windows")]
const FILENAME: &str = "ctehxk2.log";
#[cfg(not(target_os = "windows"))]
const FILENAME: &str = "libctehxk2.log";

pub fn init() {
    INIT.call_once(|| init_logger());
    debug!("Logging initialized!");
}

fn init_logger() {
    let config = match Settings::log_path() {
        Some(path) => init_file_logger(String::from(path)),
        _ => init_stdout_logger(),
    };

    log4rs::init_config(config).unwrap();
}

fn init_file_logger(mut path: String) -> Config {
    let appender_id = "file";
    path.push_str(FILENAME);

    let file = FileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
        .build(path)
        .unwrap();

    Config::builder()
        .appender(Appender::builder().build(appender_id, Box::new(file)))
        .logger(
            Logger::builder()
                .appender(appender_id)
                .additive(false)
                .build("ctehxk2", log_level()),
        )
        .build(
            Root::builder()
                .appender(appender_id)
                .build(LevelFilter::Error),
        )
        .unwrap()
}

fn init_stdout_logger() -> Config {
    let appender_id = "stdout";
    let stdout = ConsoleAppender::builder().build();

    Config::builder()
        .appender(Appender::builder().build(appender_id, Box::new(stdout)))
        .logger(
            Logger::builder()
                .appender(appender_id)
                .additive(false)
                .build("ctehxk2", log_level()),
        )
        .build(
            Root::builder()
                .appender(appender_id)
                .build(LevelFilter::Error),
        )
        .unwrap()
}

fn log_level() -> LevelFilter {
    return match LevelFilter::from_str(&Settings::log_level()) {
        Ok(log_level) => log_level,
        _ => LevelFilter::Error,
    };
}
<commit_msg>adjust debug logging<commit_after>use super::settings::Settings;
use log::LevelFilter;
use log4rs;
use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use std::str::FromStr;
use std::sync::{Once, ONCE_INIT};

static INIT: Once = ONCE_INIT;

#[cfg(target_os = "windows")]
const FILENAME: &str = "ctehxk2.log";
#[cfg(not(target_os = "windows"))]
const FILENAME: &str = "libctehxk2.log";

pub fn init() {
    INIT.call_once(|| init_logger());
}

fn init_logger() {
    let config = match Settings::log_path() {
        Some(path) => init_file_logger(String::from(path)),
        _ => init_stdout_logger(),
    };

    log4rs::init_config(config).unwrap();
    debug!("Logging initialized!");
}

fn init_file_logger(mut path: String) -> Config {
    let appender_id = "file";
    path.push_str(FILENAME);

    let file = FileAppender::builder()
        .encoder(Box::new(PatternEncoder::new("{d} {l} {M}: {m}{n}")))
        .build(path)
        .unwrap();

    Config::builder()
        .appender(Appender::builder().build(appender_id, Box::new(file)))
        .logger(
            Logger::builder()
                .appender(appender_id)
                .additive(false)
                .build("ctehxk2", log_level()),
        )
        .build(
            Root::builder()
                .appender(appender_id)
                .build(LevelFilter::Error),
        )
        .unwrap()
}

fn init_stdout_logger() -> Config {
    let appender_id = "stdout";
    let stdout = ConsoleAppender::builder().build();

    Config::builder()
        .appender(Appender::builder().build(appender_id, Box::new(stdout)))
        .logger(
            Logger::builder()
                .appender(appender_id)
                .additive(false)
                .build("ctehxk2", log_level()),
        )
        .build(
            Root::builder()
                .appender(appender_id)
                .build(LevelFilter::Error),
        )
        .unwrap()
}

fn log_level() -> LevelFilter {
    return match LevelFilter::from_str(&Settings::log_level()) {
        Ok(log_level) => log_level,
        _ => LevelFilter::Error,
    };
}
<|endoftext|>


<commit_before>//! Contains types related to 2D image data.

use std::ops;
use std::mem;
use std::slice;
use gl;

/// A trait for types that that contain 2D image data, which can
/// be uploaded to a texture using a [`Texture2dBuilder`]
/// (../context/texture_context/struct.Texture2dBuilder)
/// or using the [`gl.image_2d`]
/// (../context/texture_context/trait.ContextTextureExt.html#method.image_2d)
/// method.
///
/// See [`Pixels`](struct.Pixels.html) for a simple `Image2d`.
pub trait Image2d {
    /// Get the width of the image, in texels.
    fn width(&self) -> usize;

    /// Get the height of the image, in texels.
    fn height(&self) -> usize;

    /// Get the format of the image data that is returned by the
    /// [`texel_bytes`](trait.Image2d.html#tymethod.texel_bytes) method.
    fn format(&self) -> ImageFormat;

    /// Get the raw texel data of the image data, as a `u8` slice.
    fn texel_bytes(&self) -> &[u8];
}

/// A single OpenGL color value, with `u8` components laid out
/// as a C struct in RGBA order. This type is the simplest implementation
/// of [`Image2d`](trait.Image2d.html), which allows it to be uploaded
/// to a texture.
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Pixel {
    /// The red component.
    pub r: u8,

    /// The green component.
    pub g: u8,

    /// The blue component.
    pub b: u8,

    /// The alpha component.
    pub a: u8
}

impl Pixel {
    /// Create an RGBA color, provided each color component.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b_a(0xAA, 0xBB, 0xCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    /// Create an RGBA color, provided the RGB components and using
    /// `0xFF` as the A value.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b(0xAA, 0xBB, 0xCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discared
    /// let pixel = glitter::Pixel::rgb(0x55AABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    /// Create an RGBA color value, provided the components as a packed
    /// `u32` value. The `u32` value will be read as `0xAARRGGBB`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::argb(0xDDAABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0xRRGGBBAA`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::rgba(0xAABBCCDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value, and a separate A component. The `u32` value
    /// will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discarded
    /// let pixel = glitter::Pixel::rgb_a(0x55AABBCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

/// A (heap-allocated) 2D image composed of a list of pixels.
///
/// # Example
///
/// ```
/// // Draw a red circle with a 50px radius in a 100px * 100px black image.
/// extern crate glitter;
///
/// let width = 100;
/// let height = 100;
/// let radius = 50;
///
// let (center_x, center_y) = (width as f32/2.0, height as f32/2.0);
//
// let mut pixels = glitter::Pixels::new(width, height);
// for x in 0..width {
//     for y in 0..height {
//         let dx = center_x - x as f32;
//         let dy = center_y - y as f32;
//         let distance = (dx*dx + dy*dy).sqrt();
//
//         let color = if distance < radius {
//             // The point is within the circle, so it should be red
//             glitter::Pixel::rgb(0xFF0000)
//         }
//         else {
//             // The point is outside the circle, so it should be black
//             glitter::Pixel::rgb(0x000000)
//         };
//         pixels[y][x] = color;
//     }
// }
// ```
#[derive(Clone)]
pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Pixels {
    /// Create a new image with the desired width and height.
    pub fn new(width: usize, height: usize) -> Self {
        Pixels {
            width: width,
            height: height,
            pixels: vec![Pixel::default(); width * height]
        }
    }
}

impl ops::Index<usize> for Pixels {
    type Output = [Pixel];

    fn index(&self, row: usize) -> &[Pixel] {
        debug_assert!(row < self.height);

        &self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl ops::IndexMut<usize> for Pixels {
    fn index_mut(&mut self, row: usize) -> &mut [Pixel] {
        debug_assert!(row < self.height);

        &mut self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn texel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    /// The data types for a texel.
    pub gl_enum TexelType {
        /// Each texel is 4 * 8 bits.
        pub const UnsignedByte as UNSIGNED_BYTE_TEXEL =
            gl::UNSIGNED_BYTE,

        /// Each texel is 16 bits, with 5-bit/6-bit/5-bit components.
        pub const UnsignedShort565 as UNSIGNED_SHORT_5_6_5 =
            gl::UNSIGNED_SHORT_5_6_5,

        /// Each texel is 16 bits, with 4, 4-bit components.
        pub const UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,

        /// Each texel is 16 bits, with 5-bit/5-bit/5-bit/1-bit components.
        pub const UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    /// The different texel formats.
    pub gl_enum TexelFormat {
        /// A texel contains only an alpha component.
        pub const Alpha as ALPHA = gl::ALPHA,

        /// A texel contains red, green, and blue components.
        pub const RGB as RGB = gl::RGB,

        /// A texel contains red, green, blue, and alpha components.
        pub const RGBA as RGBA = gl::RGBA
    }
}

gl_enum! {
    /// The various image formats of a renderbuffer.
    pub gl_enum RenderbufferFormat {
        /// The red, green, blue, and alpha channels are all stored with 4 bits.
        pub const RGBA4 as RGBA4 = gl::RGBA4,

        /// The red, green, and blue channels are stored with 5 bits, 6 bits,
        /// and 5 bits, respectively.
        pub const RGB565 as RGB565 = gl::RGB565,

        /// The red, green, and blue channels are stored with 5 bits, and the
        /// alpha channel is stored with 1 bit.
        pub const RGB5A1 as RGB5_A1 = gl::RGB5_A1,

        /// The renderbuffer stores a 16-bit depth component.
        pub const DepthComponent16 as DEPTH_COMPONENT16 = gl::DEPTH_COMPONENT16,

        /// The renderbuffer stores an 8-bit stencil component.
        pub const StencilIndex8 as STENCIL_INDEX8 = gl::STENCIL_INDEX8
    }
}

/// A type that contains the texel type and format that make up a 2D image.
#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    /// The texel type of the image.
    pub texel_type: TexelType,

        /// The texel format of the image.
    pub texel_format: TexelFormat
}

impl ImageFormat {
    /// Returns the RGBA image format with 8 bits per component.
    pub fn rgba8() -> Self {
        ImageFormat {
            texel_type: TexelType::UnsignedByte,
            texel_format: TexelFormat::RGBA
        }
    }
}
<commit_msg>Docs: add note about default pixel color in `Pixels`<commit_after>//! Contains types related to 2D image data.

use std::ops;
use std::mem;
use std::slice;
use gl;

/// A trait for types that that contain 2D image data, which can
/// be uploaded to a texture using a [`Texture2dBuilder`]
/// (../context/texture_context/struct.Texture2dBuilder)
/// or using the [`gl.image_2d`]
/// (../context/texture_context/trait.ContextTextureExt.html#method.image_2d)
/// method.
///
/// See [`Pixels`](struct.Pixels.html) for a simple `Image2d`.
pub trait Image2d {
    /// Get the width of the image, in texels.
    fn width(&self) -> usize;

    /// Get the height of the image, in texels.
    fn height(&self) -> usize;

    /// Get the format of the image data that is returned by the
    /// [`texel_bytes`](trait.Image2d.html#tymethod.texel_bytes) method.
    fn format(&self) -> ImageFormat;

    /// Get the raw texel data of the image data, as a `u8` slice.
    fn texel_bytes(&self) -> &[u8];
}

/// A single OpenGL color value, with `u8` components laid out
/// as a C struct in RGBA order. This type is the simplest implementation
/// of [`Image2d`](trait.Image2d.html), which allows it to be uploaded
/// to a texture.
#[derive(Debug, Clone, Copy, Default)]
#[repr(C)]
pub struct Pixel {
    /// The red component.
    pub r: u8,

    /// The green component.
    pub g: u8,

    /// The blue component.
    pub b: u8,

    /// The alpha component.
    pub a: u8
}

impl Pixel {
    /// Create an RGBA color, provided each color component.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b_a(0xAA, 0xBB, 0xCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn r_g_b_a(r: u8, g: u8, b: u8, a: u8) -> Self {
        Pixel { r: r, g: g, b: b, a: a }
    }

    /// Create an RGBA color, provided the RGB components and using
    /// `0xFF` as the A value.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::r_g_b(0xAA, 0xBB, 0xCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn r_g_b(r: u8, g: u8, b: u8) -> Self {
        Pixel::r_g_b_a(r, g, b, 0xFF)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discared
    /// let pixel = glitter::Pixel::rgb(0x55AABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xFF);
    /// ```
    pub fn rgb(rgb: u32) -> Self {
        Pixel::rgb_a(rgb, 0xFF)
    }

    /// Create an RGBA color value, provided the components as a packed
    /// `u32` value. The `u32` value will be read as `0xAARRGGBB`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::argb(0xDDAABBCC);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn argb(argb: u32) -> Self {
        let a = (argb & 0xFF000000) >> 24;
        Pixel::rgb_a(argb, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value. The `u32` value will be read as `0xRRGGBBAA`.
    ///
    /// # Examples
    /// ```
    /// let pixel = glitter::Pixel::rgba(0xAABBCCDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgba(rgba: u32) -> Self {
        let r = (rgba & 0xFF000000) >> 24;
        let g = (rgba & 0x00FF0000) >> 16;
        let b = (rgba & 0x0000FF00) >> 8;
        let a =  rgba & 0x000000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a as u8)
    }

    /// Create an RGBA color, provided the RGB components as a packed
    /// `u32` value, and a separate A component. The `u32` value
    /// will be read as `0x00RRGGBB`.
    ///
    /// # Examples
    /// ```
    /// // The `0x55` component gets discarded
    /// let pixel = glitter::Pixel::rgb_a(0x55AABBCC, 0xDD);
    /// assert_eq!(pixel.r, 0xAA);
    /// assert_eq!(pixel.g, 0xBB);
    /// assert_eq!(pixel.b, 0xCC);
    /// assert_eq!(pixel.a, 0xDD);
    /// ```
    pub fn rgb_a(rgb: u32, a: u8) -> Self {
        let r = (rgb & 0xFF0000) >> 16;
        let g = (rgb & 0x00FF00) >> 8;
        let b =  rgb & 0x0000FF;
        Pixel::r_g_b_a(r as u8, g as u8, b as u8, a)
    }
}

/// A (heap-allocated) 2D image composed of a list of pixels.
///
/// # Example
///
/// ```
/// // Draw a red circle with a 50px radius in a 100px * 100px black image.
/// extern crate glitter;
///
/// let width = 100;
/// let height = 100;
/// let radius = 50;
///
// let (center_x, center_y) = (width as f32/2.0, height as f32/2.0);
//
// let mut pixels = glitter::Pixels::new(width, height);
// for x in 0..width {
//     for y in 0..height {
//         let dx = center_x - x as f32;
//         let dy = center_y - y as f32;
//         let distance = (dx*dx + dy*dy).sqrt();
//
//         let color = if distance < radius {
//             // The point is within the circle, so it should be red
//             glitter::Pixel::rgb(0xFF0000)
//         }
//         else {
//             // The point is outside the circle, so it should be black
//             glitter::Pixel::rgb(0x000000)
//         };
//         pixels[y][x] = color;
//     }
// }
// ```
#[derive(Clone)]
pub struct Pixels {
    width: usize,
    height: usize,
    pixels: Vec<Pixel>
}

impl Pixels {
    /// Create a new image with the desired width and height. Pixels
    /// are initialized with [`Pixel::default()`]
    /// (https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default).
    pub fn new(width: usize, height: usize) -> Self {
        Pixels {
            width: width,
            height: height,
            pixels: vec![Pixel::default(); width * height]
        }
    }
}

impl ops::Index<usize> for Pixels {
    type Output = [Pixel];

    fn index(&self, row: usize) -> &[Pixel] {
        debug_assert!(row < self.height);

        &self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl ops::IndexMut<usize> for Pixels {
    fn index_mut(&mut self, row: usize) -> &mut [Pixel] {
        debug_assert!(row < self.height);

        &mut self.pixels[(row*self.width)..((row+1)*self.width)]
    }
}

impl Image2d for Pixels {
    fn width(&self) -> usize {
        self.width
    }

    fn height(&self) -> usize {
        self.height
    }

    fn format(&self) -> ImageFormat {
        ImageFormat::rgba8()
    }

    fn texel_bytes(&self) -> &[u8] {
        let len = self.pixels.len() * mem::size_of::<Pixel>();
        unsafe {
            slice::from_raw_parts(mem::transmute(&self.pixels[0]), len)
        }
    }
}

gl_enum! {
    /// The data types for a texel.
    pub gl_enum TexelType {
        /// Each texel is 4 * 8 bits.
        pub const UnsignedByte as UNSIGNED_BYTE_TEXEL =
            gl::UNSIGNED_BYTE,

        /// Each texel is 16 bits, with 5-bit/6-bit/5-bit components.
        pub const UnsignedShort565 as UNSIGNED_SHORT_5_6_5 =
            gl::UNSIGNED_SHORT_5_6_5,

        /// Each texel is 16 bits, with 4, 4-bit components.
        pub const UnsignedShort4444 as UNSIGNED_SHORT_4_4_4_4 =
            gl::UNSIGNED_SHORT_4_4_4_4,

        /// Each texel is 16 bits, with 5-bit/5-bit/5-bit/1-bit components.
        pub const UnsignedShort5551 as UNSIGNED_SHORT_5_5_5_1 =
            gl::UNSIGNED_SHORT_5_5_5_1
    }
}

gl_enum! {
    /// The different texel formats.
    pub gl_enum TexelFormat {
        /// A texel contains only an alpha component.
        pub const Alpha as ALPHA = gl::ALPHA,

        /// A texel contains red, green, and blue components.
        pub const RGB as RGB = gl::RGB,

        /// A texel contains red, green, blue, and alpha components.
        pub const RGBA as RGBA = gl::RGBA
    }
}

gl_enum! {
    /// The various image formats of a renderbuffer.
    pub gl_enum RenderbufferFormat {
        /// The red, green, blue, and alpha channels are all stored with 4 bits.
        pub const RGBA4 as RGBA4 = gl::RGBA4,

        /// The red, green, and blue channels are stored with 5 bits, 6 bits,
        /// and 5 bits, respectively.
        pub const RGB565 as RGB565 = gl::RGB565,

        /// The red, green, and blue channels are stored with 5 bits, and the
        /// alpha channel is stored with 1 bit.
        pub const RGB5A1 as RGB5_A1 = gl::RGB5_A1,

        /// The renderbuffer stores a 16-bit depth component.
        pub const DepthComponent16 as DEPTH_COMPONENT16 = gl::DEPTH_COMPONENT16,

        /// The renderbuffer stores an 8-bit stencil component.
        pub const StencilIndex8 as STENCIL_INDEX8 = gl::STENCIL_INDEX8
    }
}

/// A type that contains the texel type and format that make up a 2D image.
#[derive(Debug, Clone, Copy)]
pub struct ImageFormat {
    /// The texel type of the image.
    pub texel_type: TexelType,

        /// The texel format of the image.
    pub texel_format: TexelFormat
}

impl ImageFormat {
    /// Returns the RGBA image format with 8 bits per component.
    pub fn rgba8() -> Self {
        ImageFormat {
            texel_type: TexelType::UnsignedByte,
            texel_format: TexelFormat::RGBA
        }
    }
}
<|endoftext|>