<commit_before>//! IL entity references.
//!
//! Instructions in Cretonne IL need to reference other entities in the function. This can be other
//! parts of the function like extended basic blocks or stack slots, or it can be external entities
//! that are declared in the function preamble in the text format.
//!
//! These entity references in instruction operands are not implemented as Rust references both
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
//! references are structs wrapping a `u32` index into a table in the `Function` main data
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
//!
//! The `entities` module defines public types for the entity references along with constants
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
//! data structures use the sentinen constant, while function arguments and return values prefer
//! the more Rust-like `Option<EntityRef>` variant.
//!
//! The entity references all implement the `Display` trait in a way that matches the textual IL
//! format.

use entity_map::EntityRef;
use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::u32;

/// An opaque reference to an extended basic block in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct Ebb(u32);

impl EntityRef for Ebb {
    fn new(index: usize) -> Self {
        assert!(index < (u32::MAX as usize));
        Ebb(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

impl Ebb {
    /// Create a new EBB reference from its number. This corresponds to the ebbNN representation.
    pub fn with_number(n: u32) -> Option<Ebb> {
        if n < u32::MAX { Some(Ebb(n)) } else { None }
    }
}

/// Display an `Ebb` reference as "ebb12".
impl Display for Ebb {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ebb{}", self.0)
    }
}

/// A guaranteed invalid EBB reference.
pub const NO_EBB: Ebb = Ebb(u32::MAX);

impl Default for Ebb {
    fn default() -> Ebb {
        NO_EBB
    }
}

/// An opaque reference to an instruction in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct Inst(u32);

impl EntityRef for Inst {
    fn new(index: usize) -> Self {
        assert!(index < (u32::MAX as usize));
        Inst(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Display an `Inst` reference as "inst7".
impl Display for Inst {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "inst{}", self.0)
    }
}

/// A guaranteed invalid instruction reference.
pub const NO_INST: Inst = Inst(u32::MAX);

impl Default for Inst {
    fn default() -> Inst {
        NO_INST
    }
}

/// An opaque reference to an SSA value.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Value(u32);

impl EntityRef for Value {
    fn new(index: usize) -> Value {
        assert!(index < (u32::MAX as usize));
        Value(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Value references can either reference an instruction directly, or they can refer to the
/// extended value table.
pub enum ExpandedValue {
    /// This is the first value produced by the referenced instruction.
    Direct(Inst),

    /// This value is described in the extended value table.
    Table(usize),

    /// This is NO_VALUE.
    None,
}

impl Value {
    /// Create a `Direct` value from its number representation.
    /// This is the number in the vNN notation.
    pub fn direct_with_number(n: u32) -> Option<Value> {
        if n < u32::MAX / 2 {
            let encoding = n * 2;
            assert!(encoding < u32::MAX);
            Some(Value(encoding))
        } else {
            None
        }
    }

    /// Create a `Table` value from its number representation.
    /// This is the number in the vxNN notation.
    pub fn table_with_number(n: u32) -> Option<Value> {
        if n < u32::MAX / 2 {
            let encoding = n * 2 + 1;
            assert!(encoding < u32::MAX);
            Some(Value(encoding))
        } else {
            None
        }
    }
    /// Create a `Direct` value corresponding to the first value produced by `i`.
    pub fn new_direct(i: Inst) -> Value {
        let encoding = i.index() * 2;
        assert!(encoding < u32::MAX as usize);
        Value(encoding as u32)
    }

    /// Create a `Table` value referring to entry `i` in the `DataFlowGraph.extended_values` table.
    /// This constructor should not be used directly. Use the public `DataFlowGraph` methods to
    /// manipulate values.
    pub fn new_table(index: usize) -> Value {
        let encoding = index * 2 + 1;
        assert!(encoding < u32::MAX as usize);
        Value(encoding as u32)
    }

    /// Expand the internal representation into something useful.
    pub fn expand(&self) -> ExpandedValue {
        use self::ExpandedValue::*;
        if *self == NO_VALUE {
            return None;
        }
        let index = (self.0 / 2) as usize;
        if self.0 % 2 == 0 {
            Direct(Inst::new(index))
        } else {
            Table(index)
        }
    }

    /// Assuming that this is a direct value, get the referenced instruction.
    ///
    /// # Panics
    ///
    /// If this is not a value created with `new_direct()`.
    pub fn unwrap_direct(&self) -> Inst {
        if let ExpandedValue::Direct(inst) = self.expand() {
            inst
        } else {
            panic!("{} is not a direct value", self)
        }
    }
}

/// Display a `Value` reference as "v7" or "v2x".
impl Display for Value {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        use self::ExpandedValue::*;
        match self.expand() {
            Direct(i) => write!(fmt, "v{}", i.0),
            Table(i) => write!(fmt, "vx{}", i),
            None => write!(fmt, "NO_VALUE"),
        }
    }
}

/// A guaranteed invalid value reference.
pub const NO_VALUE: Value = Value(u32::MAX);

impl Default for Value {
    fn default() -> Value {
        NO_VALUE
    }
}

/// An opaque reference to a stack slot.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct StackSlot(u32);

impl EntityRef for StackSlot {
    fn new(index: usize) -> StackSlot {
        assert!(index < (u32::MAX as usize));
        StackSlot(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Display a `StackSlot` reference as "ss12".
impl Display for StackSlot {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "ss{}", self.0)
    }
}

/// A guaranteed invalid stack slot reference.
pub const NO_STACK_SLOT: StackSlot = StackSlot(u32::MAX);

impl Default for StackSlot {
    fn default() -> StackSlot {
        NO_STACK_SLOT
    }
}

/// An opaque reference to a jump table.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct JumpTable(u32);

impl EntityRef for JumpTable {
    fn new(index: usize) -> JumpTable {
        assert!(index < (u32::MAX as usize));
        JumpTable(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Display a `JumpTable` reference as "jt12".
impl Display for JumpTable {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "jt{}", self.0)
    }
}

/// A guaranteed invalid jump table reference.
pub const NO_JUMP_TABLE: JumpTable = JumpTable(u32::MAX);

impl Default for JumpTable {
    fn default() -> JumpTable {
        NO_JUMP_TABLE
    }
}

/// A reference to an external function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FuncRef(u32);

impl EntityRef for FuncRef {
    fn new(index: usize) -> FuncRef {
        assert!(index < (u32::MAX as usize));
        FuncRef(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Display a `FuncRef` reference as "fn12".
impl Display for FuncRef {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "fn{}", self.0)
    }
}

/// A guaranteed invalid function reference.
pub const NO_FUNC_REF: FuncRef = FuncRef(u32::MAX);

impl Default for FuncRef {
    fn default() -> FuncRef {
        NO_FUNC_REF
    }
}

/// A reference to a function signature.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct SigRef(u32);

impl EntityRef for SigRef {
    fn new(index: usize) -> SigRef {
        assert!(index < (u32::MAX as usize));
        SigRef(index as u32)
    }

    fn index(self) -> usize {
        self.0 as usize
    }
}

/// Display a `SigRef` reference as "sig12".
impl Display for SigRef {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "sig{}", self.0)
    }
}

/// A guaranteed invalid function reference.
pub const NO_SIG_REF: SigRef = SigRef(u32::MAX);

impl Default for SigRef {
    fn default() -> SigRef {
        NO_SIG_REF
    }
}

/// A reference to any of the entities defined in this module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum AnyEntity {
    /// The whole function.
    Function,
    /// An extended basic block.
    Ebb(Ebb),
    /// An instruction.
    Inst(Inst),
    /// An SSA value.
    Value(Value),
    /// A stack slot.
    StackSlot(StackSlot),
    /// A jump table.
    JumpTable(JumpTable),
    /// An external function.
    FuncRef(FuncRef),
    /// A function call signature.
    SigRef(SigRef),
}

impl Display for AnyEntity {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            AnyEntity::Function => write!(fmt, "function"),
            AnyEntity::Ebb(r) => r.fmt(fmt),
            AnyEntity::Inst(r) => r.fmt(fmt),
            AnyEntity::Value(r) => r.fmt(fmt),
            AnyEntity::StackSlot(r) => r.fmt(fmt),
            AnyEntity::JumpTable(r) => r.fmt(fmt),
            AnyEntity::FuncRef(r) => r.fmt(fmt),
            AnyEntity::SigRef(r) => r.fmt(fmt),
        }
    }
}

impl From<Ebb> for AnyEntity {
    fn from(r: Ebb) -> AnyEntity {
        AnyEntity::Ebb(r)
    }
}

impl From<Inst> for AnyEntity {
    fn from(r: Inst) -> AnyEntity {
        AnyEntity::Inst(r)
    }
}

impl From<Value> for AnyEntity {
    fn from(r: Value) -> AnyEntity {
        AnyEntity::Value(r)
    }
}

impl From<StackSlot> for AnyEntity {
    fn from(r: StackSlot) -> AnyEntity {
        AnyEntity::StackSlot(r)
    }
}

impl From<JumpTable> for AnyEntity {
    fn from(r: JumpTable) -> AnyEntity {
        AnyEntity::JumpTable(r)
    }
}

impl From<FuncRef> for AnyEntity {
    fn from(r: FuncRef) -> AnyEntity {
        AnyEntity::FuncRef(r)
    }
}

impl From<SigRef> for AnyEntity {
    fn from(r: SigRef) -> AnyEntity {
        AnyEntity::SigRef(r)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::u32;
    use entity_map::EntityRef;

    #[test]
    fn value_with_number() {
        assert_eq!(Value::direct_with_number(0).unwrap().to_string(), "v0");
        assert_eq!(Value::direct_with_number(1).unwrap().to_string(), "v1");
        assert_eq!(Value::table_with_number(0).unwrap().to_string(), "vx0");
        assert_eq!(Value::table_with_number(1).unwrap().to_string(), "vx1");

        assert_eq!(Value::direct_with_number(u32::MAX / 2), None);
        assert_eq!(match Value::direct_with_number(u32::MAX / 2 - 1).unwrap().expand() {
                       ExpandedValue::Direct(i) => i.index() as u32,
                       _ => u32::MAX,
                   },
                   u32::MAX / 2 - 1);

        assert_eq!(Value::table_with_number(u32::MAX / 2), None);
        assert_eq!(match Value::table_with_number(u32::MAX / 2 - 1).unwrap().expand() {
                       ExpandedValue::Table(i) => i as u32,
                       _ => u32::MAX,
                   },
                   u32::MAX / 2 - 1);
    }
}
<commit_msg>Move duplicated entity code into a macro.<commit_after>//! IL entity references.
//!
//! Instructions in Cretonne IL need to reference other entities in the function. This can be other
//! parts of the function like extended basic blocks or stack slots, or it can be external entities
//! that are declared in the function preamble in the text format.
//!
//! These entity references in instruction operands are not implemented as Rust references both
//! because Rust's ownership and mutability rules make it difficult, and because 64-bit pointers
//! take up a lot of space, and we want a compact in-memory representation. Instead, entity
//! references are structs wrapping a `u32` index into a table in the `Function` main data
//! structure. There is a separate index type for each entity type, so we don't lose type safety.
//!
//! The `entities` module defines public types for the entity references along with constants
//! representing an invalid reference. We prefer to use `Option<EntityRef>` whenever possible, but
//! unfortunately that type is twice as large as the 32-bit index type on its own. Thus, compact
//! data structures use the sentinen constant, while function arguments and return values prefer
//! the more Rust-like `Option<EntityRef>` variant.
//!
//! The entity references all implement the `Display` trait in a way that matches the textual IL
//! format.

use entity_map::EntityRef;
use packed_option::ReservedValue;
use std::default::Default;
use std::fmt::{self, Display, Formatter};
use std::u32;

// Implement the common traits for a 32-bit entity reference.
macro_rules! entity_impl {
    // Basic traits.
    ($entity:ident) => {
        impl EntityRef for $entity {
            fn new(index: usize) -> Self {
                assert!(index < (u32::MAX as usize));
                $entity(index as u32)
            }

            fn index(self) -> usize {
                self.0 as usize
            }
        }

        impl ReservedValue for $entity {
            fn reserved_value() -> $entity {
                $entity(u32::MAX)
            }
        }
    };

    // Include basic `Display` impl using the given display prefix.
    // Display an `Ebb` reference as "ebb12".
    ($entity:ident, $display_prefix:expr) => {
        entity_impl!($entity);

        impl Display for $entity {
            fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
                write!(fmt, "{}{}", $display_prefix, self.0)
            }
        }
    }
}

/// An opaque reference to an extended basic block in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct Ebb(u32);
entity_impl!(Ebb, "ebb");

impl Ebb {
    /// Create a new EBB reference from its number. This corresponds to the ebbNN representation.
    pub fn with_number(n: u32) -> Option<Ebb> {
        if n < u32::MAX { Some(Ebb(n)) } else { None }
    }
}

/// A guaranteed invalid EBB reference.
pub const NO_EBB: Ebb = Ebb(u32::MAX);

impl Default for Ebb {
    fn default() -> Ebb {
        NO_EBB
    }
}

/// An opaque reference to an instruction in a function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
pub struct Inst(u32);
entity_impl!(Inst, "inst");

/// A guaranteed invalid instruction reference.
pub const NO_INST: Inst = Inst(u32::MAX);

impl Default for Inst {
    fn default() -> Inst {
        NO_INST
    }
}

/// An opaque reference to an SSA value.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct Value(u32);
entity_impl!(Value);

/// Value references can either reference an instruction directly, or they can refer to the
/// extended value table.
pub enum ExpandedValue {
    /// This is the first value produced by the referenced instruction.
    Direct(Inst),

    /// This value is described in the extended value table.
    Table(usize),

    /// This is NO_VALUE.
    None,
}

impl Value {
    /// Create a `Direct` value from its number representation.
    /// This is the number in the vNN notation.
    pub fn direct_with_number(n: u32) -> Option<Value> {
        if n < u32::MAX / 2 {
            let encoding = n * 2;
            assert!(encoding < u32::MAX);
            Some(Value(encoding))
        } else {
            None
        }
    }

    /// Create a `Table` value from its number representation.
    /// This is the number in the vxNN notation.
    pub fn table_with_number(n: u32) -> Option<Value> {
        if n < u32::MAX / 2 {
            let encoding = n * 2 + 1;
            assert!(encoding < u32::MAX);
            Some(Value(encoding))
        } else {
            None
        }
    }
    /// Create a `Direct` value corresponding to the first value produced by `i`.
    pub fn new_direct(i: Inst) -> Value {
        let encoding = i.index() * 2;
        assert!(encoding < u32::MAX as usize);
        Value(encoding as u32)
    }

    /// Create a `Table` value referring to entry `i` in the `DataFlowGraph.extended_values` table.
    /// This constructor should not be used directly. Use the public `DataFlowGraph` methods to
    /// manipulate values.
    pub fn new_table(index: usize) -> Value {
        let encoding = index * 2 + 1;
        assert!(encoding < u32::MAX as usize);
        Value(encoding as u32)
    }

    /// Expand the internal representation into something useful.
    pub fn expand(&self) -> ExpandedValue {
        use self::ExpandedValue::*;
        if *self == NO_VALUE {
            return None;
        }
        let index = (self.0 / 2) as usize;
        if self.0 % 2 == 0 {
            Direct(Inst::new(index))
        } else {
            Table(index)
        }
    }

    /// Assuming that this is a direct value, get the referenced instruction.
    ///
    /// # Panics
    ///
    /// If this is not a value created with `new_direct()`.
    pub fn unwrap_direct(&self) -> Inst {
        if let ExpandedValue::Direct(inst) = self.expand() {
            inst
        } else {
            panic!("{} is not a direct value", self)
        }
    }
}

/// Display a `Value` reference as "v7" or "v2x".
impl Display for Value {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        use self::ExpandedValue::*;
        match self.expand() {
            Direct(i) => write!(fmt, "v{}", i.0),
            Table(i) => write!(fmt, "vx{}", i),
            None => write!(fmt, "NO_VALUE"),
        }
    }
}

/// A guaranteed invalid value reference.
pub const NO_VALUE: Value = Value(u32::MAX);

impl Default for Value {
    fn default() -> Value {
        NO_VALUE
    }
}

/// An opaque reference to a stack slot.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct StackSlot(u32);
entity_impl!(StackSlot, "ss");

/// A guaranteed invalid stack slot reference.
pub const NO_STACK_SLOT: StackSlot = StackSlot(u32::MAX);

impl Default for StackSlot {
    fn default() -> StackSlot {
        NO_STACK_SLOT
    }
}

/// An opaque reference to a jump table.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct JumpTable(u32);
entity_impl!(JumpTable, "jt");

/// A guaranteed invalid jump table reference.
pub const NO_JUMP_TABLE: JumpTable = JumpTable(u32::MAX);

impl Default for JumpTable {
    fn default() -> JumpTable {
        NO_JUMP_TABLE
    }
}

/// A reference to an external function.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FuncRef(u32);
entity_impl!(FuncRef, "fn");

/// A guaranteed invalid function reference.
pub const NO_FUNC_REF: FuncRef = FuncRef(u32::MAX);

impl Default for FuncRef {
    fn default() -> FuncRef {
        NO_FUNC_REF
    }
}

/// A reference to a function signature.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct SigRef(u32);
entity_impl!(SigRef, "sig");

/// A guaranteed invalid function reference.
pub const NO_SIG_REF: SigRef = SigRef(u32::MAX);

impl Default for SigRef {
    fn default() -> SigRef {
        NO_SIG_REF
    }
}

/// A reference to any of the entities defined in this module.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum AnyEntity {
    /// The whole function.
    Function,
    /// An extended basic block.
    Ebb(Ebb),
    /// An instruction.
    Inst(Inst),
    /// An SSA value.
    Value(Value),
    /// A stack slot.
    StackSlot(StackSlot),
    /// A jump table.
    JumpTable(JumpTable),
    /// An external function.
    FuncRef(FuncRef),
    /// A function call signature.
    SigRef(SigRef),
}

impl Display for AnyEntity {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            AnyEntity::Function => write!(fmt, "function"),
            AnyEntity::Ebb(r) => r.fmt(fmt),
            AnyEntity::Inst(r) => r.fmt(fmt),
            AnyEntity::Value(r) => r.fmt(fmt),
            AnyEntity::StackSlot(r) => r.fmt(fmt),
            AnyEntity::JumpTable(r) => r.fmt(fmt),
            AnyEntity::FuncRef(r) => r.fmt(fmt),
            AnyEntity::SigRef(r) => r.fmt(fmt),
        }
    }
}

impl From<Ebb> for AnyEntity {
    fn from(r: Ebb) -> AnyEntity {
        AnyEntity::Ebb(r)
    }
}

impl From<Inst> for AnyEntity {
    fn from(r: Inst) -> AnyEntity {
        AnyEntity::Inst(r)
    }
}

impl From<Value> for AnyEntity {
    fn from(r: Value) -> AnyEntity {
        AnyEntity::Value(r)
    }
}

impl From<StackSlot> for AnyEntity {
    fn from(r: StackSlot) -> AnyEntity {
        AnyEntity::StackSlot(r)
    }
}

impl From<JumpTable> for AnyEntity {
    fn from(r: JumpTable) -> AnyEntity {
        AnyEntity::JumpTable(r)
    }
}

impl From<FuncRef> for AnyEntity {
    fn from(r: FuncRef) -> AnyEntity {
        AnyEntity::FuncRef(r)
    }
}

impl From<SigRef> for AnyEntity {
    fn from(r: SigRef) -> AnyEntity {
        AnyEntity::SigRef(r)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::u32;
    use entity_map::EntityRef;

    #[test]
    fn value_with_number() {
        assert_eq!(Value::direct_with_number(0).unwrap().to_string(), "v0");
        assert_eq!(Value::direct_with_number(1).unwrap().to_string(), "v1");
        assert_eq!(Value::table_with_number(0).unwrap().to_string(), "vx0");
        assert_eq!(Value::table_with_number(1).unwrap().to_string(), "vx1");

        assert_eq!(Value::direct_with_number(u32::MAX / 2), None);
        assert_eq!(match Value::direct_with_number(u32::MAX / 2 - 1).unwrap().expand() {
                       ExpandedValue::Direct(i) => i.index() as u32,
                       _ => u32::MAX,
                   },
                   u32::MAX / 2 - 1);

        assert_eq!(Value::table_with_number(u32::MAX / 2), None);
        assert_eq!(match Value::table_with_number(u32::MAX / 2 - 1).unwrap().expand() {
                       ExpandedValue::Table(i) => i as u32,
                       _ => u32::MAX,
                   },
                   u32::MAX / 2 - 1);
    }
}
<|endoftext|>


<commit_before>use super::{AliasSource, AliasedField, FieldAliasMapper};

use crate::associations::HasTable;
use crate::backend::Backend;
use crate::dsl::{Filter, Select};
use crate::expression::{Expression, SelectableExpression, ValidGrouping};
use crate::query_builder::nodes::StaticQueryFragment;
use crate::query_builder::{AsQuery, AstPass, FromClause, QueryFragment, QueryId, SelectStatement};
use crate::query_dsl::methods::*;
use crate::query_dsl::QueryDsl;
use crate::query_source::{AppearsInFromClause, Column, Never, QuerySource, Table, TableNotEqual};
use crate::result::QueryResult;

#[derive(Debug, Clone, Copy, Default)]
/// Represents an alias within diesel's query builder
///
/// See [alias!] for more details.
pub struct Alias<S> {
    source: S,
}

impl<S: AliasSource> Alias<S> {
    /// Maps a single field of the source table in this alias
    pub fn field<F>(self, field: F) -> AliasedField<S, F>
    where
        F: Column<Table = S::Table>,
    {
        AliasedField {
            _alias_source: self.source,
            _field: field,
        }
    }
    /// Maps multiple fields of the source table in this alias (takes in tuples)
    pub fn fields<Fields>(self, fields: Fields) -> <Fields as FieldAliasMapper<S>>::Out
    where
        Fields: FieldAliasMapper<S>,
    {
        fields.map(self)
    }
}

impl<S> Alias<S> {
    #[doc(hidden)]
    /// May be used to create an alias. Used by the [`alias!`] macro.
    pub const fn new(source: S) -> Self {
        Self { source }
    }
}

impl<S> QueryId for Alias<S> {
    type QueryId = ();

    const HAS_STATIC_QUERY_ID: bool = false;
}

impl<S> QuerySource for Alias<S>
where
    S: AliasSource,
    S::Table: QuerySource + HasTable<Table = S::Table>,
    <S::Table as QuerySource>::DefaultSelection: FieldAliasMapper<S>,
    <<S::Table as QuerySource>::DefaultSelection as FieldAliasMapper<S>>::Out:
        SelectableExpression<Self>,
{
    type FromClause = Self;
    type DefaultSelection =
        <<S::Table as QuerySource>::DefaultSelection as FieldAliasMapper<S>>::Out;

    fn from_clause(&self) -> Self::FromClause {
        *self
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.fields(S::Table::table().default_selection())
    }
}

impl<S, DB> QueryFragment<DB> for Alias<S>
where
    S: AliasSource,
    DB: Backend,
    S::Table: StaticQueryFragment,
    <S::Table as StaticQueryFragment>::Component: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        <S::Table as StaticQueryFragment>::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
        pass.push_sql(" AS ");
        pass.push_identifier(S::NAME)?;
        Ok(())
    }
}

impl<S> AsQuery for Alias<S>
where
    S: AliasSource,
    S::Table: AsQuery,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: ValidGrouping<()>,
{
    type SqlType = <<Self as QuerySource>::DefaultSelection as Expression>::SqlType;
    type Query = SelectStatement<FromClause<Self>>;

    fn as_query(self) -> Self::Query {
        SelectStatement::simple(self)
    }
}

impl<S: AliasSource> QueryDsl for Alias<S> {}

impl<S, Predicate> FilterDsl<Predicate> for Alias<S>
where
    S: AliasSource,
    Self: AsQuery,
    <Self as AsQuery>::Query: FilterDsl<Predicate>,
{
    type Output = Filter<<Self as AsQuery>::Query, Predicate>;

    fn filter(self, predicate: Predicate) -> Self::Output {
        self.as_query().filter(predicate)
    }
}

impl<S, Selection> SelectDsl<Selection> for Alias<S>
where
    Selection: Expression,
    Self: AsQuery,
    S: AliasSource,
    <Self as AsQuery>::Query: SelectDsl<Selection>,
{
    type Output = Select<<Self as AsQuery>::Query, Selection>;

    fn select(self, selection: Selection) -> Self::Output {
        self.as_query().select(selection)
    }
}

impl<S, QS> AppearsInFromClause<QS> for Alias<S>
where
    S: AliasSource,
    S::Table: AliasAppearsInFromClause<S, QS>,
{
    type Count = <S::Table as AliasAppearsInFromClause<S, QS>>::Count;
}
#[doc(hidden)]
/// This trait is used to allow external crates to implement
/// `AppearsInFromClause<QS> for Alias<S>`
///
/// without running in conflicting impl issues
pub trait AliasAppearsInFromClause<S, QS> {
    /// Will be passed on to the `impl AppearsInFromClause<QS>`
    type Count;
}
#[doc(hidden)]
/// This trait is used to allow external crates to implement
/// `AppearsInFromClause<Alias<S2>> for Alias<S1>`
///
/// without running in conflicting impl issues
pub trait AliasAliasAppearsInFromClause<T2, S1, S2> {
    /// Will be passed on to the `impl AppearsInFromClause<QS>`
    type Count;
}
impl<T1, S1, S2> AliasAppearsInFromClause<S1, Alias<S2>> for T1
where
    S2: AliasSource,
    T1: AliasAliasAppearsInFromClause<S2::Table, S1, S2>,
{
    type Count = <T1 as AliasAliasAppearsInFromClause<S2::Table, S1, S2>>::Count;
}

// impl<S: AliasSource<Table=T1>> AppearsInFromClause<T2> for Alias<S>
// where T1 != T2
impl<T1, T2, S> AliasAppearsInFromClause<S, T2> for T1
where
    T1: TableNotEqual<T2> + Table,
    T2: Table,
    S: AliasSource<Table = T1>,
{
    type Count = Never;
}

// impl<S1, S2> AppearsInFromClause<Alias<S1>> for Alias<S2>
// where S1: AliasSource, S2: AliasSource, S1::Table != S2::Table
impl<T1, T2, S1, S2> AliasAliasAppearsInFromClause<T1, S2, S1> for T2
where
    T1: TableNotEqual<T2> + Table,
    T2: Table,
    S1: AliasSource<Table = T1>,
    S2: AliasSource<Table = T2>,
{
    type Count = Never;
}

impl<S> AppearsInFromClause<Alias<S>> for ()
where
    S: AliasSource,
{
    type Count = Never;
}
<commit_msg>Allow caching through QueryId for aliases<commit_after>use super::{AliasSource, AliasedField, FieldAliasMapper};

use crate::associations::HasTable;
use crate::backend::Backend;
use crate::dsl::{Filter, Select};
use crate::expression::{Expression, SelectableExpression, ValidGrouping};
use crate::query_builder::nodes::StaticQueryFragment;
use crate::query_builder::{AsQuery, AstPass, FromClause, QueryFragment, QueryId, SelectStatement};
use crate::query_dsl::methods::*;
use crate::query_dsl::QueryDsl;
use crate::query_source::{AppearsInFromClause, Column, Never, QuerySource, Table, TableNotEqual};
use crate::result::QueryResult;

#[derive(Debug, Clone, Copy, Default)]
/// Represents an alias within diesel's query builder
///
/// See [alias!] for more details.
pub struct Alias<S> {
    source: S,
}

impl<S: AliasSource> Alias<S> {
    /// Maps a single field of the source table in this alias
    pub fn field<F>(self, field: F) -> AliasedField<S, F>
    where
        F: Column<Table = S::Table>,
    {
        AliasedField {
            _alias_source: self.source,
            _field: field,
        }
    }
    /// Maps multiple fields of the source table in this alias (takes in tuples)
    pub fn fields<Fields>(self, fields: Fields) -> <Fields as FieldAliasMapper<S>>::Out
    where
        Fields: FieldAliasMapper<S>,
    {
        fields.map(self)
    }
}

impl<S> Alias<S> {
    #[doc(hidden)]
    /// May be used to create an alias. Used by the [`alias!`] macro.
    pub const fn new(source: S) -> Self {
        Self { source }
    }
}

impl<S> QueryId for Alias<S>
where
    Self: 'static,
{
    type QueryId = Self;
    const HAS_STATIC_QUERY_ID: bool = true;
}

impl<S> QuerySource for Alias<S>
where
    S: AliasSource,
    S::Table: QuerySource + HasTable<Table = S::Table>,
    <S::Table as QuerySource>::DefaultSelection: FieldAliasMapper<S>,
    <<S::Table as QuerySource>::DefaultSelection as FieldAliasMapper<S>>::Out:
        SelectableExpression<Self>,
{
    type FromClause = Self;
    type DefaultSelection =
        <<S::Table as QuerySource>::DefaultSelection as FieldAliasMapper<S>>::Out;

    fn from_clause(&self) -> Self::FromClause {
        *self
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.fields(S::Table::table().default_selection())
    }
}

impl<S, DB> QueryFragment<DB> for Alias<S>
where
    S: AliasSource,
    DB: Backend,
    S::Table: StaticQueryFragment,
    <S::Table as StaticQueryFragment>::Component: QueryFragment<DB>,
{
    fn walk_ast<'b>(&'b self, mut pass: AstPass<'_, 'b, DB>) -> QueryResult<()> {
        <S::Table as StaticQueryFragment>::STATIC_COMPONENT.walk_ast(pass.reborrow())?;
        pass.push_sql(" AS ");
        pass.push_identifier(S::NAME)?;
        Ok(())
    }
}

impl<S> AsQuery for Alias<S>
where
    S: AliasSource,
    S::Table: AsQuery,
    Self: QuerySource,
    <Self as QuerySource>::DefaultSelection: ValidGrouping<()>,
{
    type SqlType = <<Self as QuerySource>::DefaultSelection as Expression>::SqlType;
    type Query = SelectStatement<FromClause<Self>>;

    fn as_query(self) -> Self::Query {
        SelectStatement::simple(self)
    }
}

impl<S: AliasSource> QueryDsl for Alias<S> {}

impl<S, Predicate> FilterDsl<Predicate> for Alias<S>
where
    S: AliasSource,
    Self: AsQuery,
    <Self as AsQuery>::Query: FilterDsl<Predicate>,
{
    type Output = Filter<<Self as AsQuery>::Query, Predicate>;

    fn filter(self, predicate: Predicate) -> Self::Output {
        self.as_query().filter(predicate)
    }
}

impl<S, Selection> SelectDsl<Selection> for Alias<S>
where
    Selection: Expression,
    Self: AsQuery,
    S: AliasSource,
    <Self as AsQuery>::Query: SelectDsl<Selection>,
{
    type Output = Select<<Self as AsQuery>::Query, Selection>;

    fn select(self, selection: Selection) -> Self::Output {
        self.as_query().select(selection)
    }
}

impl<S, QS> AppearsInFromClause<QS> for Alias<S>
where
    S: AliasSource,
    S::Table: AliasAppearsInFromClause<S, QS>,
{
    type Count = <S::Table as AliasAppearsInFromClause<S, QS>>::Count;
}
#[doc(hidden)]
/// This trait is used to allow external crates to implement
/// `AppearsInFromClause<QS> for Alias<S>`
///
/// without running in conflicting impl issues
pub trait AliasAppearsInFromClause<S, QS> {
    /// Will be passed on to the `impl AppearsInFromClause<QS>`
    type Count;
}
#[doc(hidden)]
/// This trait is used to allow external crates to implement
/// `AppearsInFromClause<Alias<S2>> for Alias<S1>`
///
/// without running in conflicting impl issues
pub trait AliasAliasAppearsInFromClause<T2, S1, S2> {
    /// Will be passed on to the `impl AppearsInFromClause<QS>`
    type Count;
}
impl<T1, S1, S2> AliasAppearsInFromClause<S1, Alias<S2>> for T1
where
    S2: AliasSource,
    T1: AliasAliasAppearsInFromClause<S2::Table, S1, S2>,
{
    type Count = <T1 as AliasAliasAppearsInFromClause<S2::Table, S1, S2>>::Count;
}

// impl<S: AliasSource<Table=T1>> AppearsInFromClause<T2> for Alias<S>
// where T1 != T2
impl<T1, T2, S> AliasAppearsInFromClause<S, T2> for T1
where
    T1: TableNotEqual<T2> + Table,
    T2: Table,
    S: AliasSource<Table = T1>,
{
    type Count = Never;
}

// impl<S1, S2> AppearsInFromClause<Alias<S1>> for Alias<S2>
// where S1: AliasSource, S2: AliasSource, S1::Table != S2::Table
impl<T1, T2, S1, S2> AliasAliasAppearsInFromClause<T1, S2, S1> for T2
where
    T1: TableNotEqual<T2> + Table,
    T2: Table,
    S1: AliasSource<Table = T1>,
    S2: AliasSource<Table = T2>,
{
    type Count = Never;
}

impl<S> AppearsInFromClause<Alias<S>> for ()
where
    S: AliasSource,
{
    type Count = Never;
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate direct_composition;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use direct_composition::DirectComposition;
use std::sync::mpsc;
use webrender::api;
use winit::os::windows::WindowExt;
use glutin::dpi::LogicalSize;

fn main() {
    let mut events_loop = winit::EventsLoop::new();

    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx });

    let window = winit::WindowBuilder::new()
        .with_title("WebRender + ANGLE + DirectComposition")
        .with_dimensions(LogicalSize::new(1024., 768.))
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);
    let factor = window.get_hidpi_factor() as f32;

    let mut clicks: usize = 0;
    let mut offset_y = 100.;
    let size = api::DeviceUintSize::new;
    let mut rects = [
        Rectangle::new(&composition, &notifier, factor, size(300, 200), 0., 0.2, 0.4, 1.),
        Rectangle::new(&composition, &notifier, factor, size(400, 300), 0., 0.5, 0., 0.5),
    ];
    rects[0].render(factor, &rx);
    rects[1].render(factor, &rx);

    rects[0].visual.set_offset_x(100.);
    rects[0].visual.set_offset_y(50.);

    rects[1].visual.set_offset_x(200.);
    rects[1].visual.set_offset_y(offset_y);

    composition.commit();

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::CloseRequested => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    rects[1].visual.set_offset_y(offset_y);
                    composition.commit();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    clicks += 1;
                    let rect = &mut rects[clicks % 2];
                    rect.color.g += 0.1;
                    rect.color.g %= 1.;
                    rect.render(factor, &rx)
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _)
    }
}

struct Rectangle {
    visual: direct_composition::AngleVisual,
    renderer: Option<webrender::Renderer>,
    api: api::RenderApi,
    document_id: api::DocumentId,
    size: api::DeviceUintSize,
    color: api::ColorF,
}

impl Rectangle {
    fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
           device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32)
           -> Self {
        let visual = composition.create_angle_visual(size.width, size.height);
        visual.make_current();

        let (renderer, sender) = webrender::Renderer::new(
            composition.gleam.clone(),
            notifier.clone(),
            webrender::RendererOptions {
                clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
                device_pixel_ratio,
                ..webrender::RendererOptions::default()
            },
        ).unwrap();
        let api = sender.create_api();

       Rectangle {
            visual,
            renderer: Some(renderer),
            document_id: api.add_document(size, 0),
            api,
            size,
            color: api::ColorF { r, g, b, a },
        }
    }

    fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) {
        self.visual.make_current();

        let pipeline_id = api::PipelineId(0, 0);
        let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size);

        let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size);

        let region = api::ComplexClipRegion::new(
            rect,
            api::BorderRadius::uniform(20.),
            api::ClipMode::Clip
        );
        let clip_id = builder.define_clip(rect, vec![region], None);
        builder.push_clip_id(clip_id);

        builder.push_rect(&api::PrimitiveInfo::new(rect), self.color);

        builder.pop_clip_id();

        let mut transaction = api::Transaction::new();
        transaction.set_display_list(
            api::Epoch(0),
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        transaction.set_root_pipeline(pipeline_id);
        transaction.generate_frame();
        self.api.send_transaction(self.document_id, transaction);
        rx.recv().unwrap();
        let renderer = self.renderer.as_mut().unwrap();
        renderer.update();
        renderer.render(self.size).unwrap();
        let _ = renderer.flush_pipeline_info();
        self.visual.present();
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        self.renderer.take().unwrap().deinit()
    }
}

#[derive(Clone)]
struct Notifier {
    events_proxy: winit::EventsLoopProxy,
    tx: mpsc::Sender<()>,
}

impl api::RenderNotifier for Notifier {
    fn clone(&self) -> Box<api::RenderNotifier> {
        Box::new(Clone::clone(self))
    }

    fn wake_up(&self) {
        self.tx.send(()).unwrap();
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: api::DocumentId,
                       _: bool,
                       _: bool,
                       _: Option<u64>) {
        self.wake_up();
    }
}
<commit_msg>enable WS_EX_NOREDIRECTIONBITMAP<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate direct_composition;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate winit;

use direct_composition::DirectComposition;
use std::sync::mpsc;
use webrender::api;
use winit::os::windows::{WindowExt, WindowBuilderExt};
use glutin::dpi::LogicalSize;

fn main() {
    let mut events_loop = winit::EventsLoop::new();

    let (tx, rx) = mpsc::channel();
    let notifier = Box::new(Notifier { events_proxy: events_loop.create_proxy(), tx });

    let window = winit::WindowBuilder::new()
        .with_title("WebRender + ANGLE + DirectComposition")
        .with_dimensions(LogicalSize::new(1024., 768.))
        .with_decorations(true)
        .with_transparency(true)
        .with_no_redirection_bitmap(true)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);
    let factor = window.get_hidpi_factor() as f32;

    let mut clicks: usize = 0;
    let mut offset_y = 100.;
    let size = api::DeviceUintSize::new;
    let mut rects = [
        Rectangle::new(&composition, &notifier, factor, size(300, 200), 0., 0.2, 0.4, 1.),
        Rectangle::new(&composition, &notifier, factor, size(400, 300), 0., 0.5, 0., 0.5),
    ];
    rects[0].render(factor, &rx);
    rects[1].render(factor, &rx);

    rects[0].visual.set_offset_x(100.);
    rects[0].visual.set_offset_y(50.);

    rects[1].visual.set_offset_x(200.);
    rects[1].visual.set_offset_y(offset_y);

    composition.commit();

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::CloseRequested => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(pos) => pos.y as f32,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    rects[1].visual.set_offset_y(offset_y);
                    composition.commit();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    clicks += 1;
                    let rect = &mut rects[clicks % 2];
                    rect.color.g += 0.1;
                    rect.color.g %= 1.;
                    rect.render(factor, &rx)
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _)
    }
}

struct Rectangle {
    visual: direct_composition::AngleVisual,
    renderer: Option<webrender::Renderer>,
    api: api::RenderApi,
    document_id: api::DocumentId,
    size: api::DeviceUintSize,
    color: api::ColorF,
}

impl Rectangle {
    fn new(composition: &DirectComposition, notifier: &Box<Notifier>,
           device_pixel_ratio: f32, size: api::DeviceUintSize, r: f32, g: f32, b: f32, a: f32)
           -> Self {
        let visual = composition.create_angle_visual(size.width, size.height);
        visual.make_current();

        let (renderer, sender) = webrender::Renderer::new(
            composition.gleam.clone(),
            notifier.clone(),
            webrender::RendererOptions {
                clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
                device_pixel_ratio,
                ..webrender::RendererOptions::default()
            },
        ).unwrap();
        let api = sender.create_api();

       Rectangle {
            visual,
            renderer: Some(renderer),
            document_id: api.add_document(size, 0),
            api,
            size,
            color: api::ColorF { r, g, b, a },
        }
    }

    fn render(&mut self, device_pixel_ratio: f32, rx: &mpsc::Receiver<()>) {
        self.visual.make_current();

        let pipeline_id = api::PipelineId(0, 0);
        let layout_size = self.size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
        let mut builder = api::DisplayListBuilder::new(pipeline_id, layout_size);

        let rect = euclid::TypedRect::new(euclid::TypedPoint2D::zero(), layout_size);

        let region = api::ComplexClipRegion::new(
            rect,
            api::BorderRadius::uniform(20.),
            api::ClipMode::Clip
        );
        let clip_id = builder.define_clip(rect, vec![region], None);
        builder.push_clip_id(clip_id);

        builder.push_rect(&api::PrimitiveInfo::new(rect), self.color);

        builder.pop_clip_id();

        let mut transaction = api::Transaction::new();
        transaction.set_display_list(
            api::Epoch(0),
            None,
            layout_size,
            builder.finalize(),
            true,
        );
        transaction.set_root_pipeline(pipeline_id);
        transaction.generate_frame();
        self.api.send_transaction(self.document_id, transaction);
        rx.recv().unwrap();
        let renderer = self.renderer.as_mut().unwrap();
        renderer.update();
        renderer.render(self.size).unwrap();
        let _ = renderer.flush_pipeline_info();
        self.visual.present();
    }
}

impl Drop for Rectangle {
    fn drop(&mut self) {
        self.renderer.take().unwrap().deinit()
    }
}

#[derive(Clone)]
struct Notifier {
    events_proxy: winit::EventsLoopProxy,
    tx: mpsc::Sender<()>,
}

impl api::RenderNotifier for Notifier {
    fn clone(&self) -> Box<api::RenderNotifier> {
        Box::new(Clone::clone(self))
    }

    fn wake_up(&self) {
        self.tx.send(()).unwrap();
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: api::DocumentId,
                       _: bool,
                       _: bool,
                       _: Option<u64>) {
        self.wake_up();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

extern crate url;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;

use url::{Url, UrlParser};

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

fn main() {
    let docs = env::args().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut url = Url::from_file_path(&docs).unwrap();
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut url, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
}

struct FileEntry {
    source: String,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

impl FileEntry {
    fn parse_ids(&mut self,
                file: &Path,
                contents: &str,
                errors: &mut bool)
{
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i| {
                let frag = fragment.trim_left_matches("#").to_owned();
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`",
                             file.display(), i, fragment);
                }
            });
        }
    }
}

fn walk(cache: &mut Cache,
        root: &Path,
        dir: &Path,
        url: &mut Url,
        errors: &mut bool)
{
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        url.path_mut().unwrap().push(entry.file_name().into_string().unwrap());
        if kind.is_dir() {
            walk(cache, root, &path, url, errors);
        } else {
            let pretty_path = check(cache, root, &path, url, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to to reduce memory-usage
                entry.source = String::new();
            }
        }
        url.path_mut().unwrap().pop();
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         base: &Url,
         errors: &mut bool) -> Option<PathBuf>
{
    // ignore js files as they are not prone to errors as the rest of the
    // documentation is and they otherwise bring up false positives.
    if file.extension().and_then(|s| s.to_str()) == Some("js") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") ||
       file.ends_with("collections/string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("collections/struct.BTreeSet.html") ||
       file.ends_with("collections/btree_map/struct.BTreeMap.html") ||
       file.ends_with("collections/hash_map/struct.HashMap.html") {
        return None;
    }

    if file.ends_with("std/sys/ext/index.html") {
        return None;
    }

    if let Some(file) = file.to_str() {
        // FIXME(#31948)
        if file.contains("ParseFloatError") {
            return None;
        }
        // weird reexports, but this module is on its way out, so chalk it up to
        // "rustdoc weirdness" and move on from there
        if file.contains("scoped_tls") {
            return None;
        }
    }

    let mut parser = UrlParser::new();
    parser.base_url(base);

    let res = load_file(cache, root, PathBuf::from(file), false, false);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file).unwrap()
                                   .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i| {
        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path. If either of these fail then we
        // just keep going.
        let (parsed_url, path) = match url_to_file_path(&parser, url) {
            Some((url, path)) => (url, PathBuf::from(path)),
            None => return,
        };

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                return;
            }
            let res = load_file(cache, root, path.clone(), true, false);
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => panic!(format!("{}", err)),
                Err(LoadError::BrokenRedirect(target, _)) => {
                    print!("{}:{}: broken redirect to {}",
                           pretty_file.display(), i + 1, target.display());
                    return;
                }
            };

            if let Some(ref fragment) = parsed_url.fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment  ",
                           pretty_file.display(), i + 1);
                    println!("`#{}` pointing to `{}`",
                             fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: PathBuf,
             follow_redirects: bool,
             is_redirect: bool) -> Result<(PathBuf, String), LoadError> {
    let mut contents = String::new();
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let maybe_redirect = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            contents = entry.get().source.clone();
            None
        },
        Entry::Vacant(entry) => {
            let mut fp = try!(File::open(file.clone()).map_err(|err| {
                if is_redirect {
                    LoadError::BrokenRedirect(file.clone(), err)
                } else {
                    LoadError::IOError(err)
                }
            }));
            try!(fp.read_to_string(&mut contents)
                   .map_err(|err| LoadError::IOError(err)));

            let maybe = if follow_redirects {
                maybe_redirect(&contents)
            } else {
                None
            };
            if maybe.is_none() {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            maybe
        },
    };
    let base = Url::from_file_path(&file).unwrap();
    let mut parser = UrlParser::new();
    parser.base_url(&base);

    match maybe_redirect.and_then(|url| url_to_file_path(&parser, &url)) {
        Some((_, redirect_file)) => {
            assert!(follow_redirects);
            let path = PathBuf::from(redirect_file);
            load_file(cache, root, path, follow_redirects, true)
        }
        None => Ok((pretty_file, contents))
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> {
    parser.parse(url).ok().and_then(|parsed_url| {
        parsed_url.to_file_path().ok().map(|f| (parsed_url, f))
    })
}

fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str,
                                               attr: &str,
                                               mut f: F)
{
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len() ..];
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            f(url, i)
        }
    }
}
<commit_msg>Don't check(=cache) redirect pages<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

extern crate url;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;

use url::{Url, UrlParser};

use Redirect::*;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {:?}", stringify!($e), e),
    })
}

fn main() {
    let docs = env::args().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut url = Url::from_file_path(&docs).unwrap();
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut url, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
    IsRedirect,
}

enum Redirect {
    SkipRedirect,
    FromRedirect(bool),
}

struct FileEntry {
    source: String,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

impl FileEntry {
    fn parse_ids(&mut self,
                file: &Path,
                contents: &str,
                errors: &mut bool)
{
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i| {
                let frag = fragment.trim_left_matches("#").to_owned();
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`",
                             file.display(), i, fragment);
                }
            });
        }
    }
}

fn walk(cache: &mut Cache,
        root: &Path,
        dir: &Path,
        url: &mut Url,
        errors: &mut bool)
{
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        url.path_mut().unwrap().push(entry.file_name().into_string().unwrap());
        if kind.is_dir() {
            walk(cache, root, &path, url, errors);
        } else {
            let pretty_path = check(cache, root, &path, url, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to to reduce memory-usage
                entry.source = String::new();
            }
        }
        url.path_mut().unwrap().pop();
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         base: &Url,
         errors: &mut bool) -> Option<PathBuf>
{
    // ignore js files as they are not prone to errors as the rest of the
    // documentation is and they otherwise bring up false positives.
    if file.extension().and_then(|s| s.to_str()) == Some("js") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") ||
       file.ends_with("collections/string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("collections/struct.BTreeSet.html") ||
       file.ends_with("collections/btree_map/struct.BTreeMap.html") ||
       file.ends_with("collections/hash_map/struct.HashMap.html") {
        return None;
    }

    if file.ends_with("std/sys/ext/index.html") {
        return None;
    }

    if let Some(file) = file.to_str() {
        // FIXME(#31948)
        if file.contains("ParseFloatError") {
            return None;
        }
        // weird reexports, but this module is on its way out, so chalk it up to
        // "rustdoc weirdness" and move on from there
        if file.contains("scoped_tls") {
            return None;
        }
    }

    let mut parser = UrlParser::new();
    parser.base_url(base);

    let res = load_file(cache, root, PathBuf::from(file), SkipRedirect);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file).unwrap()
                                   .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i| {
        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path. If either of these fail then we
        // just keep going.
        let (parsed_url, path) = match url_to_file_path(&parser, url) {
            Some((url, path)) => (url, PathBuf::from(path)),
            None => return,
        };

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                return;
            }
            let res = load_file(cache, root, path.clone(), FromRedirect(false));
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => panic!(format!("{}", err)),
                Err(LoadError::BrokenRedirect(target, _)) => {
                    print!("{}:{}: broken redirect to {}",
                           pretty_file.display(), i + 1, target.display());
                    return;
                }
                Err(LoadError::IsRedirect) => unreachable!(),
            };

            if let Some(ref fragment) = parsed_url.fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment  ",
                           pretty_file.display(), i + 1);
                    println!("`#{}` pointing to `{}`",
                             fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: PathBuf,
             redirect: Redirect) -> Result<(PathBuf, String), LoadError> {
    let mut contents = String::new();
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let maybe_redirect = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            contents = entry.get().source.clone();
            None
        },
        Entry::Vacant(entry) => {
            let mut fp = try!(File::open(file.clone()).map_err(|err| {
                if let FromRedirect(true) = redirect {
                    LoadError::BrokenRedirect(file.clone(), err)
                } else {
                    LoadError::IOError(err)
                }
            }));
            try!(fp.read_to_string(&mut contents)
                   .map_err(|err| LoadError::IOError(err)));

            let maybe = maybe_redirect(&contents);
            if maybe.is_some() {
                if let SkipRedirect = redirect {
                    return Err(LoadError::IsRedirect);
                }
            } else {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            maybe
        },
    };
    let base = Url::from_file_path(&file).unwrap();
    let mut parser = UrlParser::new();
    parser.base_url(&base);

    match maybe_redirect.and_then(|url| url_to_file_path(&parser, &url)) {
        Some((_, redirect_file)) => {
            let path = PathBuf::from(redirect_file);
            load_file(cache, root, path, FromRedirect(true))
        }
        None => Ok((pretty_file, contents))
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn url_to_file_path(parser: &UrlParser, url: &str) -> Option<(Url, PathBuf)> {
    parser.parse(url).ok().and_then(|parsed_url| {
        parsed_url.to_file_path().ok().map(|f| (parsed_url, f))
    })
}

fn with_attrs_in_source<F: FnMut(&str, usize)>(contents: &str,
                                               attr: &str,
                                               mut f: F)
{
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len() ..];
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            f(url, i)
        }
    }
}
<|endoftext|>


<commit_before>// Connection Pool-esque construct used to queue up
// and asynchronously execute Postgres queries

use std::collections::VecDeque;
use std::thread;
use std::sync::{Arc, Mutex};

use postgres;
use futures::stream::{Stream, channel, Sender, Receiver};
use futures::{Future, oneshot, Complete};

use transport::postgres::get_client;

type QueryError = postgres::error::Error;
type SenderQueue = Arc<Mutex<VecDeque<Sender<(String, Complete<()>), ()>>>>;
type QueryQueue = Arc<Mutex<VecDeque<String>>>;

pub struct QueryServer {
    conn_count: usize, // how many connections to open
    query_queue: QueryQueue, // internal query queue
    conn_queue: SenderQueue, // senders for idle query threads
}

// locks the QueryQueue and returns a queued query, if there are any.
fn try_get_new_query(query_queue: QueryQueue) -> Option<String> {
    let mut qq_inner = query_queue.lock().unwrap();
    // there is a queued query
    if !qq_inner.is_empty() {
        return Some(qq_inner.pop_front().unwrap())
    }else{
        // No new queries
        return None
    }
}

// executes the query and blocks the calling thread until it completes
#[allow(unused_must_use)]
fn execute_query(query: String, client: &postgres::Connection) {
    client.execute(query.as_str(), &[])
        /*.map_err(|err| println!("Error saving tick: {:?}", err) )*/;
}

// Creates a query processor that awaits requests
fn init_query_processor(rx: Receiver<(String, Complete<()>), ()>, query_queue: QueryQueue) {
    // get a connection to the postgres database
    let client = get_client().expect("Couldn't create postgres connection.");
    // Handler for new queries from main thread
    // This blocks the worker thread until a new message is received
    // .wait() consumes the stream immediately, so the main thread has to wait
    // for the worker to push a message saying it's done before sending more messages
    for tup in rx.wait() {
        let (query, done_tx) = tup.unwrap();
        execute_query(query, &client);
        // keep trying to get queued queries to exeucte until the queue is empty
        while let Some(new_query) = try_get_new_query(query_queue.clone()) {
            execute_query(new_query, &client);
        }
        // Let the main thread know it's safe to use the sender again
        // This essentially indicates that the worker thread is idle
        done_tx.complete(());
    }
}

impl QueryServer {
    pub fn new(conn_count: usize) -> QueryServer {
        let mut conn_queue = VecDeque::with_capacity(conn_count);
        let query_queue = Arc::new(Mutex::new(VecDeque::new()));
        for _ in 0..conn_count {
            // channel for getting the Sender back from the worker thread
            let (tx, rx) = channel::<(String, Complete<()>), ()>();
            let qq_copy = query_queue.clone();
            thread::spawn(move || { init_query_processor(rx, qq_copy) });
            // store the sender which can be used to send queries
            // to the worker in the connection queue
            conn_queue.push_back(tx);
        }

        QueryServer {
            conn_count: conn_count,
            query_queue: query_queue,
            conn_queue: Arc::new(Mutex::new(conn_queue))
        }
    }

    // queues up a query to execute that doesn't return a result
    pub fn execute(&mut self, query: String) {
        // no connections available
        let temp_lock_res = self.conn_queue.lock().unwrap().is_empty();
        // Force the guard locking conn_queue to go out of scope
        // this prevents the lock from being held through the entire if/else
        let copy_res = temp_lock_res.clone();
        if copy_res {
            // push query to the query queue
            self.query_queue.lock().unwrap().push_back(query);
        }else{
            let tx = self.conn_queue.lock().unwrap().pop_front().unwrap();
            let cq_clone = self.conn_queue.clone();
            // future for notifying main thread when query is done and worker is idle
            let (c, o) = oneshot::<()>();
            tx.send(Ok((query, c))).and_then(|new_tx| {
                // Wait until the worker thread signals that it is idle
                o.and_then(move |_| {
                    // Put the Sender for the newly idle worker into the connection queue
                    cq_clone.lock().unwrap().push_back(new_tx);
                    Ok(())
                }).forget();
                Ok(())
            }).forget();
        }
    }
}
<commit_msg>QueryServer code tweaks from Codereview stackexchange<commit_after>// Connection Pool-esque construct used to queue up
// and asynchronously execute Postgres queries

use std::collections::VecDeque;
use std::thread;
use std::sync::{Arc, Mutex};

use postgres;
use futures::stream::{Stream, channel, Sender, Receiver};
use futures::{Future, oneshot, Complete};

use transport::postgres::get_client;

type SenderQueue = Arc<Mutex<VecDeque<Sender<(String, Complete<()>), ()>>>>;
type QueryQueue = Arc<Mutex<VecDeque<String>>>;

pub struct QueryServer {
    conn_count: usize, // how many connections to open
    query_queue: QueryQueue, // internal query queue
    conn_queue: SenderQueue, // senders for idle query threads
}

// locks the QueryQueue and returns a queued query, if there are any.
fn try_get_new_query(query_queue: &Mutex<VecDeque<String>>) -> Option<String> {
    let mut qq_inner = query_queue.lock().unwrap();
    qq_inner.pop_front()
}

// executes the query and blocks the calling thread until it completes
fn execute_query(query: &str, client: &postgres::Connection) {
    let _ = client.execute(query, &[]);
}

// Creates a query processor that awaits requests
fn init_query_processor(rx: Receiver<(String, Complete<()>), ()>, query_queue: QueryQueue) {
    // get a connection to the postgres database
    let client = get_client().expect("Couldn't create postgres connection.");
    // Handler for new queries from main thread
    // This blocks the worker thread until a new message is received
    // .wait() consumes the stream immediately, so the main thread has to wait
    // for the worker to push a message saying it's done before sending more messages
    for tup in rx.wait() {
        let (query, done_tx) = tup.unwrap();
        execute_query(query.as_str(), &client);
        // keep trying to get queued queries to execute until the queue is empty
        while let Some(new_query) = try_get_new_query(&*query_queue.clone()) {
            execute_query(new_query.as_str(), &client);
        }
        // Let the main thread know it's safe to use the sender again
        // This essentially indicates that the worker thread is idle
        done_tx.complete(());
    }
}

impl QueryServer {
    pub fn new(conn_count: usize) -> QueryServer {
        let mut conn_queue = VecDeque::with_capacity(conn_count);
        let query_queue = Arc::new(Mutex::new(VecDeque::new()));
        for _ in 0..conn_count {
            // channel for getting the Sender back from the worker thread
            let (tx, rx) = channel::<(String, Complete<()>), ()>();
            let qq_copy = query_queue.clone();
            thread::spawn(move || init_query_processor(rx, qq_copy) );
            // store the sender which can be used to send queries
            // to the worker in the connection queue
            conn_queue.push_back(tx);
        }

        QueryServer {
            conn_count: conn_count,
            query_queue: query_queue,
            conn_queue: Arc::new(Mutex::new(conn_queue))
        }
    }

    // queues up a query to execute that doesn't return a result
    pub fn execute(&mut self, query: String) {
        // no connections available
        let temp_lock_res = self.conn_queue.lock().unwrap().is_empty();
        // Force the guard locking conn_queue to go out of scope
        // this prevents the lock from being held through the entire if/else
        let copy_res = temp_lock_res.clone();
        if copy_res {
            // push query to the query queue
            self.query_queue.lock().unwrap().push_back(query);
        } else {
            let tx = self.conn_queue.lock().unwrap().pop_front().unwrap();
            let cq_clone = self.conn_queue.clone();
            // future for notifying main thread when query is done and worker is idle
            let (c, o) = oneshot::<()>();
            tx.send(Ok((query, c))).and_then(|new_tx| {
                // Wait until the worker thread signals that it is idle
                o.and_then(move |_| {
                    // Put the Sender for the newly idle worker into the connection queue
                    cq_clone.lock().unwrap().push_back(new_tx);
                    Ok(())
                }).forget();
                Ok(())
            }).forget();
        }
    }
}
<|endoftext|>