<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 https://mozilla.org/MPL/2.0/. */

//! An iterator over a list of rules.

use crate::context::QuirksMode;
use crate::media_queries::Device;
use crate::shared_lock::SharedRwLockReadGuard;
use crate::stylesheets::StylesheetInDocument;
use crate::stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
use smallvec::SmallVec;
use std::slice;

/// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'b>,
    stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
    _phantom: ::std::marker::PhantomData<C>,
}

impl<'a, 'b, C> RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    /// Creates a new `RulesIterator` to iterate over `rules`.
    pub fn new(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rules: slice::Iter<'a, CssRule>,
    ) -> Self {
        let mut stack = SmallVec::new();
        stack.push(rules);
        Self {
            device,
            quirks_mode,
            guard,
            stack,
            _phantom: ::std::marker::PhantomData,
        }
    }

    /// Skips all the remaining children of the last nested rule processed.
    pub fn skip_children(&mut self) {
        self.stack.pop();
    }
}

fn children_of_rule<'a, C>(
    rule: &'a CssRule,
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'_>,
    effective: &mut bool,
) -> slice::Iter<'a, CssRule>
where
    C: NestedRuleIterationCondition + 'static,
{
    *effective = true;
    match *rule {
        CssRule::Namespace(_) |
        CssRule::Style(_) |
        CssRule::FontFace(_) |
        CssRule::CounterStyle(_) |
        CssRule::Viewport(_) |
        CssRule::Keyframes(_) |
        CssRule::Page(_) |
        CssRule::FontFeatureValues(_) => [].iter(),
        CssRule::Import(ref import_rule) => {
            let import_rule = import_rule.read_with(guard);
            if !C::process_import(guard, device, quirks_mode, import_rule) {
                *effective = false;
                return [].iter();
            }
            import_rule.stylesheet.rules(guard).iter()
        },
        CssRule::Document(ref doc_rule) => {
            let doc_rule = doc_rule.read_with(guard);
            if !C::process_document(guard, device, quirks_mode, doc_rule) {
                *effective = false;
                return [].iter();
            }
            doc_rule.rules.read_with(guard).0.iter()
        },
        CssRule::Media(ref lock) => {
            let media_rule = lock.read_with(guard);
            if !C::process_media(guard, device, quirks_mode, media_rule) {
                *effective = false;
                return [].iter();
            }
            media_rule.rules.read_with(guard).0.iter()
        },
        CssRule::Supports(ref lock) => {
            let supports_rule = lock.read_with(guard);
            if !C::process_supports(guard, device, quirks_mode, supports_rule) {
                *effective = false;
                return [].iter();
            }
            supports_rule.rules.read_with(guard).0.iter()
        },
    }
}

impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    type Item = &'a CssRule;

    fn next(&mut self) -> Option<Self::Item> {
        while !self.stack.is_empty() {
            let rule = {
                let nested_iter = self.stack.last_mut().unwrap();
                match nested_iter.next() {
                    Some(r) => r,
                    None => {
                        self.stack.pop();
                        continue;
                    },
                }
            };

            let mut effective = true;
            let children = children_of_rule::<C>(rule, self.device, self.quirks_mode, self.guard, &mut effective);
            if !effective {
                continue;
            }

            if !children.as_slice().is_empty() {
                self.stack.push(children);
            }

            return Some(rule);
        }

        None
    }
}

/// RulesIterator.
pub trait NestedRuleIterationCondition {
    /// Whether we should process the nested rules in a given `@import` rule.
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@media` rule.
    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@-moz-document`
    /// rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool;
}

/// A struct that represents the condition that a rule applies to the document.
pub struct EffectiveRules;

impl EffectiveRules {
    /// Returns whether a given rule is effective.
    pub fn is_effective(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &CssRule,
    ) -> bool {
        match *rule {
            CssRule::Import(ref import_rule) => {
            let import_rule = import_rule.read_with(guard);
                Self::process_import(guard, device, quirks_mode, import_rule)
            },
            CssRule::Document(ref doc_rule) => {
                let doc_rule = doc_rule.read_with(guard);
                Self::process_document(guard, device, quirks_mode, doc_rule)
            },
            CssRule::Media(ref lock) => {
                let media_rule = lock.read_with(guard);
                Self::process_media(guard, device, quirks_mode, media_rule)
            },
            CssRule::Supports(ref lock) => {
                let supports_rule = lock.read_with(guard);
                Self::process_supports(guard, device, quirks_mode, supports_rule)
            },
            _ => true,
        }
    }
}

impl NestedRuleIterationCondition for EffectiveRules {
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        _quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool {
        rule.stylesheet.is_effective_for_device(device, guard)
    }

    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool {
        rule.media_queries
            .read_with(guard)
            .evaluate(device, quirks_mode)
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        device: &Device,
        _: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        rule.condition.evaluate(device)
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        rule.enabled
    }
}

/// A filter that processes all the rules in a rule list.
pub struct AllRules;

impl NestedRuleIterationCondition for AllRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &DocumentRule,
    ) -> bool {
        true
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &SupportsRule,
    ) -> bool {
        true
    }
}

/// An iterator over all the effective rules of a stylesheet.
///
/// NOTE: This iterator recurses into `@import` rules.
pub type EffectiveRulesIterator<'a, 'b> = RulesIterator<'a, 'b, EffectiveRules>;

impl<'a, 'b> EffectiveRulesIterator<'a, 'b> {
    /// Returns an iterator over the effective children of a rule, even if
    /// `rule` itself is not effective.
    pub fn effective_children(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rule: &'a CssRule,
    ) -> Self {
        let children = children_of_rule::<AllRules>(rule, device, quirks_mode, guard, &mut false);
        EffectiveRulesIterator::new(device, quirks_mode, guard, children)
    }
}
<commit_msg>style: Properly distinguish between empty children and no children in rule iterator.<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 https://mozilla.org/MPL/2.0/. */

//! An iterator over a list of rules.

use crate::context::QuirksMode;
use crate::media_queries::Device;
use crate::shared_lock::SharedRwLockReadGuard;
use crate::stylesheets::StylesheetInDocument;
use crate::stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
use smallvec::SmallVec;
use std::slice;

/// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'b>,
    stack: SmallVec<[slice::Iter<'a, CssRule>; 3]>,
    _phantom: ::std::marker::PhantomData<C>,
}

impl<'a, 'b, C> RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    /// Creates a new `RulesIterator` to iterate over `rules`.
    pub fn new(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rules: slice::Iter<'a, CssRule>,
    ) -> Self {
        let mut stack = SmallVec::new();
        stack.push(rules);
        Self {
            device,
            quirks_mode,
            guard,
            stack,
            _phantom: ::std::marker::PhantomData,
        }
    }

    /// Skips all the remaining children of the last nested rule processed.
    pub fn skip_children(&mut self) {
        self.stack.pop();
    }
}

fn children_of_rule<'a, C>(
    rule: &'a CssRule,
    device: &'a Device,
    quirks_mode: QuirksMode,
    guard: &'a SharedRwLockReadGuard<'_>,
    effective: &mut bool,
) -> Option<slice::Iter<'a, CssRule>>
where
    C: NestedRuleIterationCondition + 'static,
{
    *effective = true;
    match *rule {
        CssRule::Namespace(_) |
        CssRule::Style(_) |
        CssRule::FontFace(_) |
        CssRule::CounterStyle(_) |
        CssRule::Viewport(_) |
        CssRule::Keyframes(_) |
        CssRule::Page(_) |
        CssRule::FontFeatureValues(_) => None,
        CssRule::Import(ref import_rule) => {
            let import_rule = import_rule.read_with(guard);
            if !C::process_import(guard, device, quirks_mode, import_rule) {
                *effective = false;
                return None;
            }
            Some(import_rule.stylesheet.rules(guard).iter())
        },
        CssRule::Document(ref doc_rule) => {
            let doc_rule = doc_rule.read_with(guard);
            if !C::process_document(guard, device, quirks_mode, doc_rule) {
                *effective = false;
                return None;
            }
            Some(doc_rule.rules.read_with(guard).0.iter())
        },
        CssRule::Media(ref lock) => {
            let media_rule = lock.read_with(guard);
            if !C::process_media(guard, device, quirks_mode, media_rule) {
                *effective = false;
                return None;
            }
            Some(media_rule.rules.read_with(guard).0.iter())
        },
        CssRule::Supports(ref lock) => {
            let supports_rule = lock.read_with(guard);
            if !C::process_supports(guard, device, quirks_mode, supports_rule) {
                *effective = false;
                return None;
            }
            Some(supports_rule.rules.read_with(guard).0.iter())
        },
    }
}

impl<'a, 'b, C> Iterator for RulesIterator<'a, 'b, C>
where
    'b: 'a,
    C: NestedRuleIterationCondition + 'static,
{
    type Item = &'a CssRule;

    fn next(&mut self) -> Option<Self::Item> {
        while !self.stack.is_empty() {
            let rule = {
                let nested_iter = self.stack.last_mut().unwrap();
                match nested_iter.next() {
                    Some(r) => r,
                    None => {
                        self.stack.pop();
                        continue;
                    },
                }
            };

            let mut effective = true;
            let children = children_of_rule::<C>(rule, self.device, self.quirks_mode, self.guard, &mut effective);
            if !effective {
                continue;
            }

            if let Some(children) = children {
                // NOTE: It's important that `children` gets pushed even if
                // empty, so that `skip_children()` works as expected.
                self.stack.push(children);
            }

            return Some(rule);
        }

        None
    }
}

/// RulesIterator.
pub trait NestedRuleIterationCondition {
    /// Whether we should process the nested rules in a given `@import` rule.
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@media` rule.
    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@-moz-document`
    /// rule.
    fn process_document(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &DocumentRule,
    ) -> bool;

    /// Whether we should process the nested rules in a given `@supports` rule.
    fn process_supports(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &SupportsRule,
    ) -> bool;
}

/// A struct that represents the condition that a rule applies to the document.
pub struct EffectiveRules;

impl EffectiveRules {
    /// Returns whether a given rule is effective.
    pub fn is_effective(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &CssRule,
    ) -> bool {
        match *rule {
            CssRule::Import(ref import_rule) => {
            let import_rule = import_rule.read_with(guard);
                Self::process_import(guard, device, quirks_mode, import_rule)
            },
            CssRule::Document(ref doc_rule) => {
                let doc_rule = doc_rule.read_with(guard);
                Self::process_document(guard, device, quirks_mode, doc_rule)
            },
            CssRule::Media(ref lock) => {
                let media_rule = lock.read_with(guard);
                Self::process_media(guard, device, quirks_mode, media_rule)
            },
            CssRule::Supports(ref lock) => {
                let supports_rule = lock.read_with(guard);
                Self::process_supports(guard, device, quirks_mode, supports_rule)
            },
            _ => true,
        }
    }
}

impl NestedRuleIterationCondition for EffectiveRules {
    fn process_import(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        _quirks_mode: QuirksMode,
        rule: &ImportRule,
    ) -> bool {
        rule.stylesheet.is_effective_for_device(device, guard)
    }

    fn process_media(
        guard: &SharedRwLockReadGuard,
        device: &Device,
        quirks_mode: QuirksMode,
        rule: &MediaRule,
    ) -> bool {
        rule.media_queries
            .read_with(guard)
            .evaluate(device, quirks_mode)
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        device: &Device,
        _: QuirksMode,
        rule: &DocumentRule,
    ) -> bool {
        rule.condition.evaluate(device)
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        rule: &SupportsRule,
    ) -> bool {
        rule.enabled
    }
}

/// A filter that processes all the rules in a rule list.
pub struct AllRules;

impl NestedRuleIterationCondition for AllRules {
    fn process_import(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &ImportRule,
    ) -> bool {
        true
    }

    fn process_media(_: &SharedRwLockReadGuard, _: &Device, _: QuirksMode, _: &MediaRule) -> bool {
        true
    }

    fn process_document(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &DocumentRule,
    ) -> bool {
        true
    }

    fn process_supports(
        _: &SharedRwLockReadGuard,
        _: &Device,
        _: QuirksMode,
        _: &SupportsRule,
    ) -> bool {
        true
    }
}

/// An iterator over all the effective rules of a stylesheet.
///
/// NOTE: This iterator recurses into `@import` rules.
pub type EffectiveRulesIterator<'a, 'b> = RulesIterator<'a, 'b, EffectiveRules>;

impl<'a, 'b> EffectiveRulesIterator<'a, 'b> {
    /// Returns an iterator over the effective children of a rule, even if
    /// `rule` itself is not effective.
    pub fn effective_children(
        device: &'a Device,
        quirks_mode: QuirksMode,
        guard: &'a SharedRwLockReadGuard<'b>,
        rule: &'a CssRule,
    ) -> Self {
        let children = children_of_rule::<AllRules>(rule, device, quirks_mode, guard, &mut false);
        EffectiveRulesIterator::new(device, quirks_mode, guard, children.unwrap_or([].iter()))
    }
}
<|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.

use rustc::infer::canonical::query_result;
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::{InferCtxt, InferOk, InferResult};
use rustc::traits::query::dropck_outlives::trivial_dropck_outlives;
use rustc::traits::query::NoSolution;
use rustc::traits::{Normalized, Obligation, ObligationCause, PredicateObligation, TraitEngine};
use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Kind;
use rustc::ty::{ParamEnv, Predicate, Ty, TyCtxt};
use std::fmt;
use std::rc::Rc;
use syntax::codemap::DUMMY_SP;

pub(super) trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
    type Output;

    /// Micro-optimization: returns `Ok(x)` if we can trivially
    /// produce the output, else returns `Err(self)` back.
    fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self>;

    /// Given an infcx, performs **the kernel** of the operation: this does the
    /// key action and then, optionally, returns a set of obligations which must be proven.
    ///
    /// This method is not meant to be invoked directly: instead, one
    /// should use `fully_perform`, which will take those resulting
    /// obligations and prove them, and then process the combined
    /// results into region obligations which are returned.
    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output>;

    /// Processes the operation and all resulting obligations,
    /// returning the final result along with any region constraints
    /// (they will be given over to the NLL region solver).
    fn fully_perform(
        self,
        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
    ) -> Result<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>), TypeError<'tcx>> {
        match self.trivial_noop(infcx.tcx) {
            Ok(r) => Ok((r, None)),
            Err(op) => op.fully_perform_nontrivial(infcx),
        }
    }

    /// Helper for `fully_perform` that handles the nontrivial cases.
    #[inline(never)] // just to help with profiling
    fn fully_perform_nontrivial(
        self,
        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
    ) -> Result<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>), TypeError<'tcx>> {
        if cfg!(debug_assertions) {
            info!("fully_perform_op_and_get_region_constraint_data({:?})", self);
        }

        let mut fulfill_cx = TraitEngine::new(infcx.tcx);
        let dummy_body_id = ObligationCause::dummy().body_id;
        let InferOk { value, obligations } = infcx.commit_if_ok(|_| self.perform(infcx))?;
        debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
        fulfill_cx.register_predicate_obligations(infcx, obligations);
        if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
            infcx.tcx.sess.diagnostic().delay_span_bug(
                DUMMY_SP,
                &format!("errors selecting obligation during MIR typeck: {:?}", e),
            );
        }

        let region_obligations = infcx.take_registered_region_obligations();

        let region_constraint_data = infcx.take_and_reset_region_constraints();

        let outlives = query_result::make_query_outlives(
            infcx.tcx,
            region_obligations,
            &region_constraint_data,
        );

        if outlives.is_empty() {
            Ok((value, None))
        } else {
            Ok((value, Some(Rc::new(outlives))))
        }
    }
}

pub(super) struct CustomTypeOp<F, G> {
    closure: F,
    description: G,
}

impl<F, G> CustomTypeOp<F, G> {
    pub(super) fn new<'gcx, 'tcx, R>(closure: F, description: G) -> Self
    where
        F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>,
        G: Fn() -> String,
    {
        CustomTypeOp {
            closure,
            description,
        }
    }
}

impl<'gcx, 'tcx, F, R, G> TypeOp<'gcx, 'tcx> for CustomTypeOp<F, G>
where
    F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>,
    G: Fn() -> String,
{
    type Output = R;

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        Err(self)
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R> {
        (self.closure)(infcx)
    }
}

impl<F, G> fmt::Debug for CustomTypeOp<F, G>
where
    G: Fn() -> String,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", (self.description)())
    }
}

#[derive(Debug)]
pub(super) struct Subtype<'tcx> {
    param_env: ParamEnv<'tcx>,
    sub: Ty<'tcx>,
    sup: Ty<'tcx>,
}

impl<'tcx> Subtype<'tcx> {
    pub(super) fn new(param_env: ParamEnv<'tcx>, sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
        Self {
            param_env,
            sub,
            sup,
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for Subtype<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.sub == self.sup {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .sup(self.sup, self.sub)
    }
}

#[derive(Debug)]
pub(super) struct Eq<'tcx> {
    param_env: ParamEnv<'tcx>,
    a: Ty<'tcx>,
    b: Ty<'tcx>,
}

impl<'tcx> Eq<'tcx> {
    pub(super) fn new(param_env: ParamEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
        Self { param_env, a, b }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for Eq<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.a == self.b {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .eq(self.a, self.b)
    }
}

#[derive(Debug)]
pub(super) struct ProvePredicates<'tcx> {
    obligations: Vec<PredicateObligation<'tcx>>,
}

impl<'tcx> ProvePredicates<'tcx> {
    pub(super) fn new(
        param_env: ParamEnv<'tcx>,
        predicates: impl IntoIterator<Item = Predicate<'tcx>>,
    ) -> Self {
        ProvePredicates {
            obligations: predicates
                .into_iter()
                .map(|p| Obligation::new(ObligationCause::dummy(), param_env, p))
                .collect(),
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for ProvePredicates<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.obligations.is_empty() {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, _infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        Ok(InferOk {
            value: (),
            obligations: self.obligations,
        })
    }
}

#[derive(Debug)]
pub(super) struct Normalize<'tcx, T> {
    param_env: ParamEnv<'tcx>,
    value: T,
}

impl<'tcx, T> Normalize<'tcx, T>
where
    T: fmt::Debug + TypeFoldable<'tcx>,
{
    pub(super) fn new(param_env: ParamEnv<'tcx>, value: T) -> Self {
        Self { param_env, value }
    }
}

impl<'gcx, 'tcx, T> TypeOp<'gcx, 'tcx> for Normalize<'tcx, T>
where
    T: fmt::Debug + TypeFoldable<'tcx>,
{
    type Output = T;

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if !self.value.has_projections() {
            Ok(self.value)
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        let Normalized { value, obligations } = infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .normalize(&self.value)
            .unwrap_or_else(|NoSolution| {
                bug!("normalization of `{:?}` failed", self.value,);
            });
        Ok(InferOk { value, obligations })
    }
}

#[derive(Debug)]
pub(super) struct DropckOutlives<'tcx> {
    param_env: ParamEnv<'tcx>,
    dropped_ty: Ty<'tcx>,
}

impl<'tcx> DropckOutlives<'tcx> {
    pub(super) fn new(param_env: ParamEnv<'tcx>, dropped_ty: Ty<'tcx>) -> Self {
        DropckOutlives {
            param_env,
            dropped_ty,
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> {
    type Output = Vec<Kind<'tcx>>;

    fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if trivial_dropck_outlives(tcx, self.dropped_ty) {
            Ok(vec![])
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        Ok(infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .dropck_outlives(self.dropped_ty))
    }
}
<commit_msg>change to `crate` privacy instead of `pub(super)`<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.

use rustc::infer::canonical::query_result;
use rustc::infer::canonical::QueryRegionConstraint;
use rustc::infer::{InferCtxt, InferOk, InferResult};
use rustc::traits::query::dropck_outlives::trivial_dropck_outlives;
use rustc::traits::query::NoSolution;
use rustc::traits::{Normalized, Obligation, ObligationCause, PredicateObligation, TraitEngine};
use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::Kind;
use rustc::ty::{ParamEnv, Predicate, Ty, TyCtxt};
use std::fmt;
use std::rc::Rc;
use syntax::codemap::DUMMY_SP;

crate trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug {
    type Output;

    /// Micro-optimization: returns `Ok(x)` if we can trivially
    /// produce the output, else returns `Err(self)` back.
    fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self>;

    /// Given an infcx, performs **the kernel** of the operation: this does the
    /// key action and then, optionally, returns a set of obligations which must be proven.
    ///
    /// This method is not meant to be invoked directly: instead, one
    /// should use `fully_perform`, which will take those resulting
    /// obligations and prove them, and then process the combined
    /// results into region obligations which are returned.
    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output>;

    /// Processes the operation and all resulting obligations,
    /// returning the final result along with any region constraints
    /// (they will be given over to the NLL region solver).
    fn fully_perform(
        self,
        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
    ) -> Result<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>), TypeError<'tcx>> {
        match self.trivial_noop(infcx.tcx) {
            Ok(r) => Ok((r, None)),
            Err(op) => op.fully_perform_nontrivial(infcx),
        }
    }

    /// Helper for `fully_perform` that handles the nontrivial cases.
    #[inline(never)] // just to help with profiling
    fn fully_perform_nontrivial(
        self,
        infcx: &InferCtxt<'_, 'gcx, 'tcx>,
    ) -> Result<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>), TypeError<'tcx>> {
        if cfg!(debug_assertions) {
            info!("fully_perform_op_and_get_region_constraint_data({:?})", self);
        }

        let mut fulfill_cx = TraitEngine::new(infcx.tcx);
        let dummy_body_id = ObligationCause::dummy().body_id;
        let InferOk { value, obligations } = infcx.commit_if_ok(|_| self.perform(infcx))?;
        debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
        fulfill_cx.register_predicate_obligations(infcx, obligations);
        if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
            infcx.tcx.sess.diagnostic().delay_span_bug(
                DUMMY_SP,
                &format!("errors selecting obligation during MIR typeck: {:?}", e),
            );
        }

        let region_obligations = infcx.take_registered_region_obligations();

        let region_constraint_data = infcx.take_and_reset_region_constraints();

        let outlives = query_result::make_query_outlives(
            infcx.tcx,
            region_obligations,
            &region_constraint_data,
        );

        if outlives.is_empty() {
            Ok((value, None))
        } else {
            Ok((value, Some(Rc::new(outlives))))
        }
    }
}

crate struct CustomTypeOp<F, G> {
    closure: F,
    description: G,
}

impl<F, G> CustomTypeOp<F, G> {
    pub(super) fn new<'gcx, 'tcx, R>(closure: F, description: G) -> Self
    where
        F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>,
        G: Fn() -> String,
    {
        CustomTypeOp {
            closure,
            description,
        }
    }
}

impl<'gcx, 'tcx, F, R, G> TypeOp<'gcx, 'tcx> for CustomTypeOp<F, G>
where
    F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R>,
    G: Fn() -> String,
{
    type Output = R;

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        Err(self)
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, R> {
        (self.closure)(infcx)
    }
}

impl<F, G> fmt::Debug for CustomTypeOp<F, G>
where
    G: Fn() -> String,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", (self.description)())
    }
}

#[derive(Debug)]
crate struct Subtype<'tcx> {
    param_env: ParamEnv<'tcx>,
    sub: Ty<'tcx>,
    sup: Ty<'tcx>,
}

impl<'tcx> Subtype<'tcx> {
    crate fn new(param_env: ParamEnv<'tcx>, sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
        Self {
            param_env,
            sub,
            sup,
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for Subtype<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.sub == self.sup {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .sup(self.sup, self.sub)
    }
}

#[derive(Debug)]
crate struct Eq<'tcx> {
    param_env: ParamEnv<'tcx>,
    a: Ty<'tcx>,
    b: Ty<'tcx>,
}

impl<'tcx> Eq<'tcx> {
    crate fn new(param_env: ParamEnv<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
        Self { param_env, a, b }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for Eq<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.a == self.b {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .eq(self.a, self.b)
    }
}

#[derive(Debug)]
crate struct ProvePredicates<'tcx> {
    obligations: Vec<PredicateObligation<'tcx>>,
}

impl<'tcx> ProvePredicates<'tcx> {
    crate fn new(
        param_env: ParamEnv<'tcx>,
        predicates: impl IntoIterator<Item = Predicate<'tcx>>,
    ) -> Self {
        ProvePredicates {
            obligations: predicates
                .into_iter()
                .map(|p| Obligation::new(ObligationCause::dummy(), param_env, p))
                .collect(),
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for ProvePredicates<'tcx> {
    type Output = ();

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if self.obligations.is_empty() {
            Ok(())
        } else {
            Err(self)
        }
    }

    fn perform(self, _infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        Ok(InferOk {
            value: (),
            obligations: self.obligations,
        })
    }
}

#[derive(Debug)]
crate struct Normalize<'tcx, T> {
    param_env: ParamEnv<'tcx>,
    value: T,
}

impl<'tcx, T> Normalize<'tcx, T>
where
    T: fmt::Debug + TypeFoldable<'tcx>,
{
    crate fn new(param_env: ParamEnv<'tcx>, value: T) -> Self {
        Self { param_env, value }
    }
}

impl<'gcx, 'tcx, T> TypeOp<'gcx, 'tcx> for Normalize<'tcx, T>
where
    T: fmt::Debug + TypeFoldable<'tcx>,
{
    type Output = T;

    fn trivial_noop(self, _tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if !self.value.has_projections() {
            Ok(self.value)
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        let Normalized { value, obligations } = infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .normalize(&self.value)
            .unwrap_or_else(|NoSolution| {
                bug!("normalization of `{:?}` failed", self.value,);
            });
        Ok(InferOk { value, obligations })
    }
}

#[derive(Debug)]
crate struct DropckOutlives<'tcx> {
    param_env: ParamEnv<'tcx>,
    dropped_ty: Ty<'tcx>,
}

impl<'tcx> DropckOutlives<'tcx> {
    crate fn new(param_env: ParamEnv<'tcx>, dropped_ty: Ty<'tcx>) -> Self {
        DropckOutlives {
            param_env,
            dropped_ty,
        }
    }
}

impl<'gcx, 'tcx> TypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> {
    type Output = Vec<Kind<'tcx>>;

    fn trivial_noop(self, tcx: TyCtxt<'_, 'gcx, 'tcx>) -> Result<Self::Output, Self> {
        if trivial_dropck_outlives(tcx, self.dropped_ty) {
            Ok(vec![])
        } else {
            Err(self)
        }
    }

    fn perform(self, infcx: &InferCtxt<'_, 'gcx, 'tcx>) -> InferResult<'tcx, Self::Output> {
        Ok(infcx
            .at(&ObligationCause::dummy(), self.param_env)
            .dropck_outlives(self.dropped_ty))
    }
}
<|endoftext|>


<commit_before>extern crate serial;
extern crate cpal;

#[macro_use]
extern crate vulkano;
extern crate winit;
extern crate vulkano_win;

use serial::prelude::*;
use std::io::Read;

use winit::get_primary_monitor;
use winit::Event;

use std::sync::Arc;
use std::time::{Duration, Instant};

use vulkano::instance::Instance;
use vulkano::device::Device;
use vulkano::swapchain::{Swapchain, SurfaceTransform};
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineParams};
use vulkano::pipeline::blend::Blend;
use vulkano::pipeline::depth_stencil::DepthStencil;
use vulkano::pipeline::input_assembly::InputAssembly;
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::multisample::Multisample;
use vulkano::pipeline::viewport::{ViewportsState, Viewport, Scissor};
use vulkano::framebuffer::{Framebuffer, Subpass};
use vulkano::command_buffer;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::PrimaryCommandBufferBuilder;
use vulkano::command_buffer::Submission;
use vulkano_win::VkSurfaceBuild;

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

mod vs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/vert.glsl")}
}

mod fs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/frag.glsl")}
}

fn main() {
    println!("👗🌋 Vulkan Multitouch Frabric Visualizer | Version 0.1.0");

    // Port Init
    let mut fabric_port = serial::windows::COMPort::open("COM5").unwrap();
    let mut buf = vec![1u8; 16];
    fabric_port.configure(&SETTINGS);
    //fabric_port.set_timeout(Duration::from_secs(1));

    // Vulkan Instance
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
    };

    // Physical Device
    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
        .next()
        .expect("No vulkan device is available.");

    // OS Window
    let window = winit::WindowBuilder::new()
        .with_fullscreen(get_primary_monitor())
        .build_vk_surface(&instance)
        .unwrap();

    // Graphics Queue Supported
    let queue = physical.queue_families()
        .find(|q| q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false))
        .expect("Couldn't find a graphical queue family.");

    // Logical Device, Queues
    let (device, mut queues) = {
        let device_ext = vulkano::device::DeviceExtensions {
            khr_swapchain: true,
            ..vulkano::device::DeviceExtensions::none()
        };

        Device::new(&physical,
                    physical.supported_features(),
                    &device_ext,
                    [(queue, 0.5)].iter().cloned())
                .expect("failed to create device")
    };

    // Device Queue
    let queue = queues.next().unwrap();

    // Swapchain, Swapchain Images
    let (swapchain, images) = {

        let caps = window.surface()
            .get_capabilities(&physical)
            .expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 720]);

        let present = caps.present_modes.iter().next().unwrap();

        let alpha = caps.supported_composite_alpha.iter().next().unwrap();

        let format = caps.supported_formats[0].0;

        Swapchain::new(&device,
                       &window.surface(),
                       caps.min_image_count,
                       format,
                       dimensions,
                       1,
                       &caps.supported_usage_flags,
                       &queue,
                       SurfaceTransform::Identity,
                       alpha,
                       present,
                       true,
                       None)
                .expect("failed to create swapchain")
    };

    // VBO and IBO
    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex {
            position: [f32; 2],
            uv: [f32; 2],
        }
        impl_vertex!(Vertex, position, uv);

        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [Vertex {
                                            position: [1.0, -1.0],
                                            uv: [1.0, 0.0],
                                        },
                                        Vertex {
                                            position: [-1.0, -1.0],
                                            uv: [0.0, 0.0],
                                        },
                                        Vertex {
                                            position: [1.0, 1.0],
                                            uv: [1.0, 1.0],
                                        },
                                        Vertex {
                                            position: [-1.0, 1.0],
                                            uv: [0.0, 1.0],
                                        }]
                                               .iter()
                                               .cloned())
                .expect("failed to create VBO")
    };

    let index_buffer = {
        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [0u32, 1, 2, 1, 2, 3]
                                           .iter()
                                           .cloned())
                .expect("failed to create IBO")
    };

    // Descriptor Pool, Descriptor Set, Pipeline Layout, Uniforms
    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    let uniform_buffer = {
        CpuAccessibleBuffer::<fs::ty::Block>::from_data(&device,
                                                        &BufferUsage::all(),
                                                        Some(queue.family()),
                                                        fs::ty::Block {
                                                            mouse: [-1., -1., -1., -1.],
                                                            resolution: [images[0].dimensions()
                                                                             [0] as
                                                                         f32,
                                                                         images[0].dimensions()
                                                                             [1] as
                                                                         f32],
                                                            time: 0.,
                                                            _padding1_: 0.,
                                                            fabric: [[0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.]],
                                                        })
                .expect("failed to create Uniform Buffer")
    };

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::fs::ty::Block>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();

    let set = pipeline_layout::set0::Set::new(&descriptor_pool,
                                              &pipeline_layout,
                                              &pipeline_layout::set0::Descriptors {
                                                   uniforms: &uniform_buffer,
                                               });

    // Shaders
    let vs = vs::Shader::load(&device).expect("failed to create shader module");

    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    // Render Pass
    mod render_pass {

        use vulkano::format::Format;

        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: Format,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {}
            }
        }
    }

    let render_pass =
        render_pass::CustomRenderPass::new(&device,
                                           &render_pass::Formats {
                                                // Use the format of the images and one sample.
                                                color: (images[0].format(), 1),
                                            })
                .unwrap();

    // Graphics Pipeline
    let pipeline = GraphicsPipeline::new(&device,
                                         GraphicsPipelineParams {
                                             vertex_input: SingleBufferDefinition::new(),

                                             vertex_shader: vs.main_entry_point(),

                                             input_assembly: InputAssembly::triangle_list(),

                                             tessellation: None,

                                             geometry_shader: None,

                                             viewport: ViewportsState::Fixed {
                                                 data: vec![(Viewport {
                                                                 origin: [0.0, 0.0],
                                                                 depth_range: 0.0..1.0,
                                                                 dimensions:
                                                                     [images[0].dimensions()[0] as
                                                                      f32,
                                                                      images[0].dimensions()[1] as
                                                                      f32],
                                                             },
                                                             Scissor::irrelevant())],
                                             },

                                             raster: Default::default(),

                                             multisample: Multisample::disabled(),

                                             fragment_shader: fs.main_entry_point(),

                                             depth_stencil: DepthStencil::disabled(),

                                             blend: Blend::pass_through(),

                                             layout: &pipeline_layout,

                                             render_pass: Subpass::from(&render_pass, 0).unwrap(),
                                         })
            .unwrap();

    let framebuffers = images.iter()
        .map(|image| {
            let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
            Framebuffer::new(&render_pass,
                             dimensions,
                             render_pass::AList { color: image })
                    .unwrap()
        })
        .collect::<Vec<_>>();

    let mut submissions: Vec<Arc<Submission>> = Vec::new();
    let mut mx: f32 = -1.0;
    let mut my: f32 = -1.0;
    let mut mleft: f32 = 0.0;
    let now = Instant::now();

    loop {

        submissions.retain(|s| s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        let command_buffer = PrimaryCommandBufferBuilder::new(&device, queue.family())
            .draw_inline(&render_pass,
                         &framebuffers[image_num],
                         render_pass::ClearValues { color: [0.0, 0.0, 0.0, 1.0] })
            .draw_indexed(&pipeline,
                          &vertex_buffer,
                          &index_buffer,
                          &DynamicState::none(),
                          &set,
                          &())
            .draw_end()
            .build();

        {

            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();
            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.time = now.elapsed().as_secs() as f32 +
                                  (now.elapsed().subsec_nanos() as f32 / 1000000000.0);
            buffer_content.mouse = [mx, my, mleft, 0.0];

            buffer_content.fabric =
                [[1. - buf[3] as f32,
                  1. - buf[7] as f32,
                  1. - buf[11] as f32,
                  1. - buf[15] as f32],
                 [1. - buf[2] as f32,
                  1. - buf[6] as f32,
                  1. - buf[10] as f32,
                  1. - buf[14] as f32],
                 [1. - buf[1] as f32, 1. - buf[5] as f32, 1. - buf[9] as f32, 1. - buf[13] as f32],
                 [1. - buf[0] as f32, 1. - buf[4] as f32, 1. - buf[8] as f32, 1. - buf[12] as f32]];
        }

        submissions.push(command_buffer::submit(&command_buffer, &queue).unwrap());

        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                Event::KeyboardInput(winit::ElementState::Released,
                                     _,
                                     Some(winit::VirtualKeyCode::Escape)) => {
                    println!("Closing visualizer!");
                    return;
                }
                Event::MouseInput(winit::ElementState::Pressed, winit::MouseButton::Left) => {
                    println!("Mouse Down");
                    mleft = 1.0;
                }
                Event::MouseInput(winit::ElementState::Released, winit::MouseButton::Left) => {
                    println!("Mouse Up");
                    mleft = 0.0;
                }
                Event::MouseMoved(x, y) => {
                    mx = x as f32;
                    my = y as f32;
                }
                Event::Closed => return,
                _ => (),
            }
        }

        fabric_port.read(&mut buf[..]);
    }
}

<commit_msg>Added file read<commit_after>extern crate serial;
extern crate cpal;

#[macro_use]
extern crate vulkano;
extern crate winit;
extern crate vulkano_win;

use serial::prelude::*;
use std::io::Read;

use winit::get_primary_monitor;
use winit::Event;

use std::sync::Arc;
use std::time::{Duration, Instant};

use vulkano::instance::Instance;
use vulkano::device::Device;
use vulkano::swapchain::{Swapchain, SurfaceTransform};
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineParams};
use vulkano::pipeline::blend::Blend;
use vulkano::pipeline::depth_stencil::DepthStencil;
use vulkano::pipeline::input_assembly::InputAssembly;
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::multisample::Multisample;
use vulkano::pipeline::viewport::{ViewportsState, Viewport, Scissor};
use vulkano::framebuffer::{Framebuffer, Subpass};
use vulkano::command_buffer;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::PrimaryCommandBufferBuilder;
use vulkano::command_buffer::Submission;
use vulkano_win::VkSurfaceBuild;

const SETTINGS: serial::PortSettings = serial::PortSettings {
    baud_rate: serial::Baud9600,
    char_size: serial::Bits8,
    parity: serial::ParityNone,
    stop_bits: serial::Stop1,
    flow_control: serial::FlowNone,
};

mod vs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/vert.glsl")}
}

mod fs {
    include!{concat!(env!("OUT_DIR"), "/shaders/src/shaders/frag.glsl")}
}

fn main() {
    println!("👗🌋 Vulkan Multitouch Frabric Visualizer | Version 0.1.0");

    // Find JSON config file, if it doesn't exist, create one.
    let file = std::fs::OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("config.json");

    // Read file
    let mut contents = String::new();
    let mut f = file.unwrap();

    f.read_to_string(&mut contents)
        .unwrap();

    if contents.is_empty() {

        contents.insert_str(0, DEFAULTCONFIG);

        f.write_all(contents.as_bytes())
            .unwrap();

        println!("Writing to config file!");
    }

    // Port Init
    let mut fabric_port = serial::windows::COMPort::open("COM5").unwrap();
    let mut buf = vec![1u8; 16];
    fabric_port.configure(&SETTINGS);
    //fabric_port.set_timeout(Duration::from_secs(1));

    // Vulkan Instance
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("Failed to create Vulkan instance.")
    };

    // Physical Device
    let physical = vulkano::instance::PhysicalDevice::enumerate(&instance)
        .next()
        .expect("No vulkan device is available.");

    // OS Window
    let window = winit::WindowBuilder::new()
        .with_fullscreen(get_primary_monitor())
        .build_vk_surface(&instance)
        .unwrap();

    // Graphics Queue Supported
    let queue = physical.queue_families()
        .find(|q| q.supports_graphics() && window.surface().is_supported(q).unwrap_or(false))
        .expect("Couldn't find a graphical queue family.");

    // Logical Device, Queues
    let (device, mut queues) = {
        let device_ext = vulkano::device::DeviceExtensions {
            khr_swapchain: true,
            ..vulkano::device::DeviceExtensions::none()
        };

        Device::new(&physical,
                    physical.supported_features(),
                    &device_ext,
                    [(queue, 0.5)].iter().cloned())
                .expect("failed to create device")
    };

    // Device Queue
    let queue = queues.next().unwrap();

    // Swapchain, Swapchain Images
    let (swapchain, images) = {

        let caps = window.surface()
            .get_capabilities(&physical)
            .expect("failed to get surface capabilities");

        let dimensions = caps.current_extent.unwrap_or([1280, 720]);

        let present = caps.present_modes.iter().next().unwrap();

        let alpha = caps.supported_composite_alpha.iter().next().unwrap();

        let format = caps.supported_formats[0].0;

        Swapchain::new(&device,
                       &window.surface(),
                       caps.min_image_count,
                       format,
                       dimensions,
                       1,
                       &caps.supported_usage_flags,
                       &queue,
                       SurfaceTransform::Identity,
                       alpha,
                       present,
                       true,
                       None)
                .expect("failed to create swapchain")
    };

    // VBO and IBO
    let vertex_buffer = {
        #[derive(Debug, Clone)]
        struct Vertex {
            position: [f32; 2],
            uv: [f32; 2],
        }
        impl_vertex!(Vertex, position, uv);

        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [Vertex {
                                            position: [1.0, -1.0],
                                            uv: [1.0, 0.0],
                                        },
                                        Vertex {
                                            position: [-1.0, -1.0],
                                            uv: [0.0, 0.0],
                                        },
                                        Vertex {
                                            position: [1.0, 1.0],
                                            uv: [1.0, 1.0],
                                        },
                                        Vertex {
                                            position: [-1.0, 1.0],
                                            uv: [0.0, 1.0],
                                        }]
                                               .iter()
                                               .cloned())
                .expect("failed to create VBO")
    };

    let index_buffer = {
        CpuAccessibleBuffer::from_iter(&device,
                                       &BufferUsage::all(),
                                       Some(queue.family()),
                                       [0u32, 1, 2, 1, 2, 3]
                                           .iter()
                                           .cloned())
                .expect("failed to create IBO")
    };

    // Descriptor Pool, Descriptor Set, Pipeline Layout, Uniforms
    let descriptor_pool = vulkano::descriptor::descriptor_set::DescriptorPool::new(&device);

    let uniform_buffer = {
        CpuAccessibleBuffer::<fs::ty::Block>::from_data(&device,
                                                        &BufferUsage::all(),
                                                        Some(queue.family()),
                                                        fs::ty::Block {
                                                            mouse: [-1., -1., -1., -1.],
                                                            resolution: [images[0].dimensions()
                                                                             [0] as
                                                                         f32,
                                                                         images[0].dimensions()
                                                                             [1] as
                                                                         f32],
                                                            time: 0.,
                                                            _padding1_: 0.,
                                                            fabric: [[0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.],
                                                                     [0., 0., 0., 0.]],
                                                        })
                .expect("failed to create Uniform Buffer")
    };

    mod pipeline_layout {
        pipeline_layout!{
            set0: {
                uniforms: UniformBuffer<::fs::ty::Block>
            }
        }
    }

    let pipeline_layout = pipeline_layout::CustomPipeline::new(&device).unwrap();

    let set = pipeline_layout::set0::Set::new(&descriptor_pool,
                                              &pipeline_layout,
                                              &pipeline_layout::set0::Descriptors {
                                                   uniforms: &uniform_buffer,
                                               });

    // Shaders
    let vs = vs::Shader::load(&device).expect("failed to create shader module");

    let fs = fs::Shader::load(&device).expect("failed to create shader module");

    // Render Pass
    mod render_pass {

        use vulkano::format::Format;

        single_pass_renderpass!{
            attachments: {
                color: {
                    load: Clear,
                    store: Store,
                    format: Format,
                }
            },
            pass: {
                color: [color],
                depth_stencil: {}
            }
        }
    }

    let render_pass =
        render_pass::CustomRenderPass::new(&device,
                                           &render_pass::Formats {
                                                // Use the format of the images and one sample.
                                                color: (images[0].format(), 1),
                                            })
                .unwrap();

    // Graphics Pipeline
    let pipeline = GraphicsPipeline::new(&device,
                                         GraphicsPipelineParams {
                                             vertex_input: SingleBufferDefinition::new(),

                                             vertex_shader: vs.main_entry_point(),

                                             input_assembly: InputAssembly::triangle_list(),

                                             tessellation: None,

                                             geometry_shader: None,

                                             viewport: ViewportsState::Fixed {
                                                 data: vec![(Viewport {
                                                                 origin: [0.0, 0.0],
                                                                 depth_range: 0.0..1.0,
                                                                 dimensions:
                                                                     [images[0].dimensions()[0] as
                                                                      f32,
                                                                      images[0].dimensions()[1] as
                                                                      f32],
                                                             },
                                                             Scissor::irrelevant())],
                                             },

                                             raster: Default::default(),

                                             multisample: Multisample::disabled(),

                                             fragment_shader: fs.main_entry_point(),

                                             depth_stencil: DepthStencil::disabled(),

                                             blend: Blend::pass_through(),

                                             layout: &pipeline_layout,

                                             render_pass: Subpass::from(&render_pass, 0).unwrap(),
                                         })
            .unwrap();

    let framebuffers = images.iter()
        .map(|image| {
            let dimensions = [image.dimensions()[0], image.dimensions()[1], 1];
            Framebuffer::new(&render_pass,
                             dimensions,
                             render_pass::AList { color: image })
                    .unwrap()
        })
        .collect::<Vec<_>>();

    let mut submissions: Vec<Arc<Submission>> = Vec::new();
    let mut mx: f32 = -1.0;
    let mut my: f32 = -1.0;
    let mut mleft: f32 = 0.0;
    let now = Instant::now();

    loop {

        submissions.retain(|s| s.destroying_would_block());

        let image_num = swapchain.acquire_next_image(Duration::new(1, 0)).unwrap();

        let command_buffer = PrimaryCommandBufferBuilder::new(&device, queue.family())
            .draw_inline(&render_pass,
                         &framebuffers[image_num],
                         render_pass::ClearValues { color: [0.0, 0.0, 0.0, 1.0] })
            .draw_indexed(&pipeline,
                          &vertex_buffer,
                          &index_buffer,
                          &DynamicState::none(),
                          &set,
                          &())
            .draw_end()
            .build();

        {

            // aquiring write lock for the uniform buffer
            let mut buffer_content = uniform_buffer.write(Duration::new(1, 0)).unwrap();
            // since write lock implementd Deref and DerefMut traits,
            // we can update content directly
            buffer_content.time = now.elapsed().as_secs() as f32 +
                                  (now.elapsed().subsec_nanos() as f32 / 1000000000.0);
            buffer_content.mouse = [mx, my, mleft, 0.0];

            buffer_content.fabric =
                [[1. - buf[3] as f32,
                  1. - buf[7] as f32,
                  1. - buf[11] as f32,
                  1. - buf[15] as f32],
                 [1. - buf[2] as f32,
                  1. - buf[6] as f32,
                  1. - buf[10] as f32,
                  1. - buf[14] as f32],
                 [1. - buf[1] as f32, 1. - buf[5] as f32, 1. - buf[9] as f32, 1. - buf[13] as f32],
                 [1. - buf[0] as f32, 1. - buf[4] as f32, 1. - buf[8] as f32, 1. - buf[12] as f32]];
        }

        submissions.push(command_buffer::submit(&command_buffer, &queue).unwrap());

        swapchain.present(&queue, image_num).unwrap();

        for ev in window.window().poll_events() {
            match ev {
                Event::KeyboardInput(winit::ElementState::Released,
                                     _,
                                     Some(winit::VirtualKeyCode::Escape)) => {
                    println!("Closing visualizer!");
                    return;
                }
                Event::MouseInput(winit::ElementState::Pressed, winit::MouseButton::Left) => {
                    println!("Mouse Down");
                    mleft = 1.0;
                }
                Event::MouseInput(winit::ElementState::Released, winit::MouseButton::Left) => {
                    println!("Mouse Up");
                    mleft = 0.0;
                }
                Event::MouseMoved(x, y) => {
                    mx = x as f32;
                    my = y as f32;
                }
                Event::Closed => return,
                _ => (),
            }
        }

        fabric_port.read(&mut buf[..]);
    }
}

<|endoftext|>


<commit_before>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::{InstBuilder, InstructionData, Opcode};
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };
        let csr_type = if self.flags().is_64bit() {
            ir::types::I64
        } else {
            ir::types::I32
        };
        let csrs = abi::callee_saved_registers(&self.shared_flags);

        let mut csr_stack_size = word_size; // Size of RBP to start with
        for _reg in &csrs {
            csr_stack_size += word_size;
        }

        let stack_offset = -(csr_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: csr_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = (total_stack_size - csr_stack_size) as i64;

        // Build up list of args, which we'll append forwards to the params and
        // backwards to the returns.
        let mut csr_args = Vec::new();
        csr_args.push(ir::AbiParam::special_reg(
            csr_type,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        ));
        for reg in &csrs {
            csr_args.push(ir::AbiParam::special_reg(
                csr_type,
                ir::ArgumentPurpose::CalleeSaved,
                *reg as RegUnit,
            ));
        }

        for csr_arg in &csr_args {
            func.signature.params.push(*csr_arg);
        }
        for csr_arg in csr_args.iter().rev() {
            func.signature.returns.push(*csr_arg);
        }

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        let fp = func.dfg.append_ebb_param(entry_ebb, csr_type);

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        let mut csr_vals = Vec::new();
        for reg in &csrs {
            // Append param to entry EBB
            let csr_arg = func.dfg.append_ebb_param(entry_ebb, csr_type);

            // Assign it a location
            func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

            // Remember it so we can push it momentarily
            csr_vals.push(csr_arg);
        }

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rsp as RegUnit,
                RU::rbp as RegUnit,
            );
            if local_stack_size > 0 {
                pos.ins().adjust_sp_imm(Imm64::new(-local_stack_size));
            }

            for csr_arg in csr_vals {
                pos.ins().x86_push(csr_arg);
            }
        }

        // Find all 'return' instructions
        let mut return_insts = Vec::new();
        for ebb in func.layout.ebbs() {
            for inst in func.layout.ebb_insts(ebb) {
                if func.dfg[inst].opcode().is_return() {
                    return_insts.push(inst);
                }
            }
        }

        // Insert an epilogue directly before every 'return'
        for inst in return_insts {
            self.insert_epilogue(inst, local_stack_size, func, &csrs, csr_type);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i64,
        func: &mut ir::Function,
        csrs: &Vec<RU>,
        csr_type: ir::types::Type,
    ) {
        let mut return_values = Vec::new();

        let mut pos = EncCursor::new(func, self).at_inst(inst);
        if stack_size > 0 {
            pos.ins().adjust_sp_imm(Imm64::new(stack_size));
        }
        for reg in csrs.iter().rev() {
            let csr_ret = pos.ins().x86_pop(csr_type);
            return_values.push((csr_ret, *reg));
        }
        let fp_ret = pos.ins().x86_pop(csr_type);
        return_values.push((fp_ret, RU::rbp));

        let func = pos.func;
        for (val, reg) in return_values {
            func.locations[val] = ir::ValueLoc::Reg(reg as RegUnit);
            func.dfg.append_inst_arg(inst, val);
        }
    }
}
<commit_msg>Use layout.last_inst to find 'return' opcodes, rather than iterating.<commit_after>//! Intel Instruction Set Architectures.

pub mod settings;
mod abi;
mod binemit;
mod enc_tables;
mod registers;

use binemit::{CodeSink, MemoryCodeSink, emit_function};
use super::super::settings as shared_settings;
use isa::enc_tables::{self as shared_enc_tables, lookup_enclist, Encodings};
use isa::Builder as IsaBuilder;
use isa::{TargetIsa, RegInfo, RegClass, EncInfo, RegUnit};
use self::registers::RU;
use ir;
use regalloc;
use result;
use ir::InstBuilder;
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use cursor::{Cursor, EncCursor};

#[allow(dead_code)]
struct Isa {
    shared_flags: shared_settings::Flags,
    isa_flags: settings::Flags,
    cpumode: &'static [shared_enc_tables::Level1Entry<u16>],
}

/// Get an ISA builder for creating Intel targets.
pub fn isa_builder() -> IsaBuilder {
    IsaBuilder {
        setup: settings::builder(),
        constructor: isa_constructor,
    }
}

fn isa_constructor(
    shared_flags: shared_settings::Flags,
    builder: &shared_settings::Builder,
) -> Box<TargetIsa> {
    let level1 = if shared_flags.is_64bit() {
        &enc_tables::LEVEL1_I64[..]
    } else {
        &enc_tables::LEVEL1_I32[..]
    };
    Box::new(Isa {
        isa_flags: settings::Flags::new(&shared_flags, builder),
        shared_flags,
        cpumode: level1,
    })
}

impl TargetIsa for Isa {
    fn name(&self) -> &'static str {
        "intel"
    }

    fn flags(&self) -> &shared_settings::Flags {
        &self.shared_flags
    }

    fn register_info(&self) -> RegInfo {
        registers::INFO.clone()
    }

    fn encoding_info(&self) -> EncInfo {
        enc_tables::INFO.clone()
    }

    fn legal_encodings<'a>(
        &'a self,
        dfg: &'a ir::DataFlowGraph,
        inst: &'a ir::InstructionData,
        ctrl_typevar: ir::Type,
    ) -> Encodings<'a> {
        lookup_enclist(
            ctrl_typevar,
            inst,
            dfg,
            self.cpumode,
            &enc_tables::LEVEL2[..],
            &enc_tables::ENCLISTS[..],
            &enc_tables::LEGALIZE_ACTIONS[..],
            &enc_tables::RECIPE_PREDICATES[..],
            &enc_tables::INST_PREDICATES[..],
            self.isa_flags.predicate_view(),
        )
    }

    fn legalize_signature(&self, sig: &mut ir::Signature, current: bool) {
        abi::legalize_signature(sig, &self.shared_flags, current)
    }

    fn regclass_for_abi_type(&self, ty: ir::Type) -> RegClass {
        abi::regclass_for_abi_type(ty)
    }

    fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet {
        abi::allocatable_registers(func, &self.shared_flags)
    }

    fn emit_inst(
        &self,
        func: &ir::Function,
        inst: ir::Inst,
        divert: &mut regalloc::RegDiversions,
        sink: &mut CodeSink,
    ) {
        binemit::emit_inst(func, inst, divert, sink)
    }

    fn emit_function(&self, func: &ir::Function, sink: &mut MemoryCodeSink) {
        emit_function(func, binemit::emit_inst, sink)
    }

    fn reloc_names(&self) -> &'static [&'static str] {
        &binemit::RELOC_NAMES
    }

    fn prologue_epilogue(&self, func: &mut ir::Function) -> result::CtonResult {
        let word_size = if self.flags().is_64bit() { 8 } else { 4 };
        let csr_type = if self.flags().is_64bit() {
            ir::types::I64
        } else {
            ir::types::I32
        };
        let csrs = abi::callee_saved_registers(&self.shared_flags);

        let mut csr_stack_size = word_size; // Size of RBP to start with
        for _reg in &csrs {
            csr_stack_size += word_size;
        }

        let stack_offset = -(csr_stack_size as i32);
        let slot = ir::StackSlotData {
            kind: ir::StackSlotKind::IncomingArg,
            size: csr_stack_size,
            offset: stack_offset,
        };
        func.create_stack_slot(slot);

        let total_stack_size = layout_stack(&mut func.stack_slots, word_size)?;
        let local_stack_size = (total_stack_size - csr_stack_size) as i64;

        // Build up list of args, which we'll append forwards to the params and
        // backwards to the returns.
        let mut csr_args = Vec::new();
        csr_args.push(ir::AbiParam::special_reg(
            csr_type,
            ir::ArgumentPurpose::FramePointer,
            RU::rbp as RegUnit,
        ));
        for reg in &csrs {
            csr_args.push(ir::AbiParam::special_reg(
                csr_type,
                ir::ArgumentPurpose::CalleeSaved,
                *reg as RegUnit,
            ));
        }

        for csr_arg in &csr_args {
            func.signature.params.push(*csr_arg);
        }
        for csr_arg in csr_args.iter().rev() {
            func.signature.returns.push(*csr_arg);
        }

        // Append param to entry EBB
        let entry_ebb = func.layout.entry_block().expect("missing entry block");
        let fp = func.dfg.append_ebb_param(entry_ebb, csr_type);

        // Assign it a location
        func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

        let mut csr_vals = Vec::new();
        for reg in &csrs {
            // Append param to entry EBB
            let csr_arg = func.dfg.append_ebb_param(entry_ebb, csr_type);

            // Assign it a location
            func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

            // Remember it so we can push it momentarily
            csr_vals.push(csr_arg);
        }

        // Insert prologue
        {
            let mut pos = EncCursor::new(func, self).at_first_insertion_point(entry_ebb);
            pos.ins().x86_push(fp);
            pos.ins().copy_special(
                RU::rsp as RegUnit,
                RU::rbp as RegUnit,
            );
            if local_stack_size > 0 {
                pos.ins().adjust_sp_imm(Imm64::new(-local_stack_size));
            }

            for csr_arg in csr_vals {
                pos.ins().x86_push(csr_arg);
            }
        }

        // Find all 'return' instructions
        let mut return_insts = Vec::new();
        for ebb in func.layout.ebbs() {
            if let Some(inst) = func.layout.last_inst(ebb) {
                if func.dfg[inst].opcode().is_return() {
                    return_insts.push(inst);
                }
            }
        }

        // Insert an epilogue directly before every 'return'
        for inst in return_insts {
            self.insert_epilogue(inst, local_stack_size, func, &csrs, csr_type);
        }

        Ok(())
    }
}

impl Isa {
    fn insert_epilogue(
        &self,
        inst: ir::Inst,
        stack_size: i64,
        func: &mut ir::Function,
        csrs: &Vec<RU>,
        csr_type: ir::types::Type,
    ) {
        let mut return_values = Vec::new();

        let mut pos = EncCursor::new(func, self).at_inst(inst);
        if stack_size > 0 {
            pos.ins().adjust_sp_imm(Imm64::new(stack_size));
        }
        for reg in csrs.iter().rev() {
            let csr_ret = pos.ins().x86_pop(csr_type);
            return_values.push((csr_ret, *reg));
        }
        let fp_ret = pos.ins().x86_pop(csr_type);
        return_values.push((fp_ret, RU::rbp));

        let func = pos.func;
        for (val, reg) in return_values {
            func.locations[val] = ir::ValueLoc::Reg(reg as RegUnit);
            func.dfg.append_inst_arg(inst, val);
        }
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate gopher_core;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use futures::{future, Future, BoxFuture};
use gopher_core::{DirEntity, ItemType};
use gopher_core::{GopherRequest, GopherResponse, GopherStr, Void};
use gopher_core::proto::GopherServer;
use std::io;
use tokio_core::io::EasyBuf;
use tokio_proto::TcpServer;
use tokio_proto::streaming::{Body, Message};
use tokio_service::Service;

pub struct HelloGopherServer;

impl Service for HelloGopherServer {
    type Request = Message<GopherRequest, Body<Void, io::Error>>;
    type Response = Message<GopherResponse, Body<EasyBuf, io::Error>>;
    type Error = io::Error;
    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, message: Self::Request) -> Self::Future {
        let request = match message {
            Message::WithoutBody(request) => request,
            _ => unreachable!(),
        };

        println!("got request {:?}", request);

        let response = match &request.selector[..] {
            b"" => GopherResponse::Menu(vec![
                DirEntity {
                    item_type: ItemType::File,
                    name: GopherStr::from_latin1(b"hello, world"),
                    selector: GopherStr::from_latin1(b"hello"),
                    host: GopherStr::from_latin1(b"0.0.0.0"),
                    port: 12345,
                },
                DirEntity {
                    item_type: ItemType::File,
                    name: GopherStr::from_latin1(b"Goodbye, world"),
                    selector: GopherStr::from_latin1(b"bye"),
                    host: GopherStr::from_latin1(b"0.0.0.0"),
                    port: 12345,
                },
            ]),
            b"hello" => GopherResponse::TextFile(
                GopherStr::from_latin1(b"Hello, world.\r\nWelcome to Gopher.").into_buf()),
            b"bye" => GopherResponse::TextFile(GopherStr::from_latin1(b"Goodbye").into_buf()),
            _ => GopherResponse::error(GopherStr::from_latin1(b"File not found")),
        };

        future::ok(Message::WithoutBody(response)).boxed()
    }
}

fn main() {
    TcpServer::new(GopherServer, "0.0.0.0:12345".parse().unwrap())
        .serve(|| Ok(HelloGopherServer));
}
<commit_msg>Compatibility hack for gopher+ clients<commit_after>extern crate futures;
extern crate gopher_core;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;

use futures::{future, Future, BoxFuture};
use gopher_core::{DirEntity, ItemType};
use gopher_core::{GopherRequest, GopherResponse, GopherStr, Void};
use gopher_core::proto::GopherServer;
use std::io;
use tokio_core::io::EasyBuf;
use tokio_proto::TcpServer;
use tokio_proto::streaming::{Body, Message};
use tokio_service::Service;

pub struct HelloGopherServer;

impl Service for HelloGopherServer {
    type Request = Message<GopherRequest, Body<Void, io::Error>>;
    type Response = Message<GopherResponse, Body<EasyBuf, io::Error>>;
    type Error = io::Error;
    type Future = BoxFuture<Self::Response, Self::Error>;

    fn call(&self, message: Self::Request) -> Self::Future {
        let request = match message {
            Message::WithoutBody(request) => request,
            _ => unreachable!(),
        };

        println!("got request {:?}", request);

        let response = match &request.selector[..] {
            b"" => match request.query.as_ref() {
                None => GopherResponse::Menu(vec![
                    DirEntity {
                        item_type: ItemType::File,
                        name: GopherStr::from_latin1(b"hello, world"),
                        selector: GopherStr::from_latin1(b"hello"),
                        host: GopherStr::from_latin1(b"0.0.0.0"),
                        port: 12345,
                    },
                    DirEntity {
                        item_type: ItemType::File,
                        name: GopherStr::from_latin1(b"Goodbye, world"),
                        selector: GopherStr::from_latin1(b"bye"),
                        host: GopherStr::from_latin1(b"0.0.0.0"),
                        port: 12345,
                    },
                ]),
                // Compatibility hack for gopher+ clients:
                Some(_) => GopherResponse::TextFile(
                    GopherStr::from_latin1(b"+-1\r\n+INFO: 1Main menu\t\tlocalhost\t12345").into_buf())
            },
            b"hello" => GopherResponse::TextFile(
                GopherStr::from_latin1(b"Hello, world.\r\nWelcome to Gopher.").into_buf()),
            b"bye" => GopherResponse::TextFile(GopherStr::from_latin1(b"Goodbye").into_buf()),
            _ => GopherResponse::error(GopherStr::from_latin1(b"File not found")),
        };

        future::ok(Message::WithoutBody(response)).boxed()
    }
}

fn main() {
    TcpServer::new(GopherServer, "0.0.0.0:12345".parse().unwrap())
        .serve(|| Ok(HelloGopherServer));
}
<|endoftext|>


<commit_before>mod token;

use std::str::Chars;

use self::token::Token;

#[derive(Debug)]
struct Lexed<'a> {
    chars: Chars<'a>,
}

impl<'a> Lexed<'a> {
    fn new(chars: Chars<'a>) -> Lexed {
        Lexed {
            chars: chars,
        }
    }
}

impl<'a> Iterator for Lexed<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.chars.next() {
            Some(c) => Some(next_int(c, &mut self.chars)),
            None    => None,
        }
    }

}

fn next_int(first_char: char, chars: &mut Chars) -> Token {
    let mut s = String::new();
    s.push(first_char);
    Token::IntTok(s)
}

fn lex(chars: Chars) -> Lexed {
    Lexed::new(chars)
}

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

    fn assert_lex(input: &str, output: &[Token]) {
        let actual: Vec<Token> = lex(input.chars()).collect();
        let actual: &[Token] = actual.as_ref();
        assert_eq!(actual, output);
    }

    fn intt(chars: &str) -> Token {
        Token::IntTok(String::from(chars))
    }

    #[test]
    fn single_character_int() {
        assert_lex("3", &[intt("3")]);
        assert_lex("9", &[intt("9")]);
    }

//    #[test]
//    fn multiple_character_int() {
//        assert_lex("31", &[intt("31")]);
//
//        let long_int = "01234567891111111111012345678911111111110123456789";
//        assert_lex(long_int, &[intt(long_int)]);
//    }
}
<commit_msg>Support lexing multi-character ints<commit_after>mod token;

use std::str::Chars;

use self::token::Token;

#[derive(Debug)]
struct Lexed<'a> {
    chars: Chars<'a>,
}

impl<'a> Lexed<'a> {
    fn new(chars: Chars<'a>) -> Lexed {
        Lexed {
            chars: chars,
        }
    }
}

impl<'a> Iterator for Lexed<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.chars.next() {
            Some(c) => Some(next_int(c, &mut self.chars)),
            None    => None,
        }
    }
}

fn next_int(first_char: char, chars: &mut Chars) -> Token {
    let mut s = String::new();
    s.push(first_char);
    loop {
        match chars.next() {
            Some(c) => s.push(c),
            None => return Token::IntTok(s)
        }
    }
}

fn lex(chars: Chars) -> Lexed {
    Lexed::new(chars)
}

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

    fn assert_lex(input: &str, output: &[Token]) {
        let actual: Vec<Token> = lex(input.chars()).collect();
        let actual: &[Token] = actual.as_ref();
        assert_eq!(actual, output);
    }

    fn intt(chars: &str) -> Token {
        Token::IntTok(String::from(chars))
    }

    #[test]
    fn single_character_int() {
        assert_lex("3", &[intt("3")]);
        assert_lex("9", &[intt("9")]);
    }

    #[test]
    fn multiple_character_int() {
        assert_lex("31", &[intt("31")]);

        let long_int = "01234567891111111111012345678911111111110123456789";
        assert_lex(long_int, &[intt(long_int)]);
    }
}
<|endoftext|>


<commit_before>use ::internal_prelude::works_everywhere::*;
use ::clients::stateless;

pub mod process_testing {
    use ::internal_prelude::works_everywhere::*;
    use ::imageflow_helpers::process_testing::*;
    use super::*;
    use ::clients::stateless;

    pub trait ProcTestContextExtras {
        fn write_json<T, P: AsRef<Path>>(&self, filename: P, info: &T)
            where T: serde::Serialize;

        fn create_blank_image_here<P: AsRef<Path>>(&self,
                                                   filename_without_ext: P,
                                                   w: u32,
                                                   h: u32,
                                                   encoder: s::EncoderPreset);
    }

    pub trait ProcOutputExtras {
        fn parse_stdout_as<'de, T>(&'de self) -> std::result::Result<T, serde_json::error::Error>
            where T: serde::Deserialize<'de>;
    }

    impl ProcOutputExtras for ProcOutput {
        fn parse_stdout_as<'de, T>(&'de self) -> std::result::Result<T, serde_json::error::Error>
            where T: serde::Deserialize<'de>
        {
            serde_json::from_slice(self.stdout_bytes())
        }
    }

    impl ProcTestContextExtras for ProcTestContext {
        fn write_json<T, P: AsRef<Path>>(&self, filename: P, info: &T)
            where T: serde::Serialize
        {
            let bytes = ::serde_json::to_vec_pretty(info).unwrap();
            self.write_file(filename, &bytes);
        }

        fn create_blank_image_here<P: AsRef<Path>>(&self,
                                                   filename_without_ext: P,
                                                   w: u32,
                                                   h: u32,
                                                   encoder: s::EncoderPreset) {
            let out = BlankImage {
                w: w,
                h: h,
                encoding: encoder,
                color: s::Color::Black
            }.generate();

            let mut path = self.working_dir().join(filename_without_ext);
            path.set_extension(&out.file_ext);

            self.write_file(path.file_name().unwrap().to_str().unwrap(), &out.bytes);
        }
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum TestImageSource {
    Url(String),
    Blank(BlankImage)
}

impl TestImageSource{
    pub fn get_bytes(&self) -> Vec<u8>{
        match *self{
            TestImageSource::Url(ref url) => {
                ::imageflow_helpers::fetching::fetch_bytes(url).unwrap()
            },
            TestImageSource::Blank(ref blank) => {
                blank.generate().bytes
            }
        }
    }
}
#[derive(Clone,Debug,PartialEq)]
pub struct BlankImage{
    pub w: u32,
    pub h: u32,
    pub color: s::Color,
    pub encoding: s::EncoderPreset
}

impl BlankImage{
    fn generate(&self) -> stateless::BuildOutput{
        // Invalid read here; the result of create_canvas is not being accessed correctly.
        let req = stateless::BuildRequest {
            inputs: vec![],
            framewise: s::Framewise::Steps(vec![s::Node::CreateCanvas {
                w: self.w as usize,
                h: self.h as usize,
                format: s::PixelFormat::Bgr24,
                color: self.color.clone(),
            },
            s::Node::Encode {
                io_id: 0,
                preset: self.encoding.clone(),
            }]),
            export_graphs_to: None, /* Some(std::path::PathBuf::from(format!("./{}/{}_debug", dir, filename_without_ext))) */
        };

        let result = ::clients::stateless::LibClient::new().build(req).unwrap();
        result.outputs.into_iter().next().unwrap()
    }
}
<commit_msg>Fix test_helpers - don't use bgr24<commit_after>use ::internal_prelude::works_everywhere::*;
use ::clients::stateless;

pub mod process_testing {
    use ::internal_prelude::works_everywhere::*;
    use ::imageflow_helpers::process_testing::*;
    use super::*;
    use ::clients::stateless;

    pub trait ProcTestContextExtras {
        fn write_json<T, P: AsRef<Path>>(&self, filename: P, info: &T)
            where T: serde::Serialize;

        fn create_blank_image_here<P: AsRef<Path>>(&self,
                                                   filename_without_ext: P,
                                                   w: u32,
                                                   h: u32,
                                                   encoder: s::EncoderPreset);
    }

    pub trait ProcOutputExtras {
        fn parse_stdout_as<'de, T>(&'de self) -> std::result::Result<T, serde_json::error::Error>
            where T: serde::Deserialize<'de>;
    }

    impl ProcOutputExtras for ProcOutput {
        fn parse_stdout_as<'de, T>(&'de self) -> std::result::Result<T, serde_json::error::Error>
            where T: serde::Deserialize<'de>
        {
            serde_json::from_slice(self.stdout_bytes())
        }
    }

    impl ProcTestContextExtras for ProcTestContext {
        fn write_json<T, P: AsRef<Path>>(&self, filename: P, info: &T)
            where T: serde::Serialize
        {
            let bytes = ::serde_json::to_vec_pretty(info).unwrap();
            self.write_file(filename, &bytes);
        }

        fn create_blank_image_here<P: AsRef<Path>>(&self,
                                                   filename_without_ext: P,
                                                   w: u32,
                                                   h: u32,
                                                   encoder: s::EncoderPreset) {
            let out = BlankImage {
                w: w,
                h: h,
                encoding: encoder,
                color: s::Color::Black
            }.generate();

            let mut path = self.working_dir().join(filename_without_ext);
            path.set_extension(&out.file_ext);

            self.write_file(path.file_name().unwrap().to_str().unwrap(), &out.bytes);
        }
    }
}

#[derive(Clone,Debug,PartialEq)]
pub enum TestImageSource {
    Url(String),
    Blank(BlankImage)
}

impl TestImageSource{
    pub fn get_bytes(&self) -> Vec<u8>{
        match *self{
            TestImageSource::Url(ref url) => {
                ::imageflow_helpers::fetching::fetch_bytes(url).unwrap()
            },
            TestImageSource::Blank(ref blank) => {
                blank.generate().bytes
            }
        }
    }
}
#[derive(Clone,Debug,PartialEq)]
pub struct BlankImage{
    pub w: u32,
    pub h: u32,
    pub color: s::Color,
    pub encoding: s::EncoderPreset
}

impl BlankImage{
    fn generate(&self) -> stateless::BuildOutput{
        // Invalid read here; the result of create_canvas is not being accessed correctly.
        let req = stateless::BuildRequest {
            inputs: vec![],
            framewise: s::Framewise::Steps(vec![s::Node::CreateCanvas {
                w: self.w as usize,
                h: self.h as usize,
                format: s::PixelFormat::Bgr32,
                color: self.color.clone(),
            },
            s::Node::Encode {
                io_id: 0,
                preset: self.encoding.clone(),
            }]),
            export_graphs_to: None, /* Some(std::path::PathBuf::from(format!("./{}/{}_debug", dir, filename_without_ext))) */
        };

        let result = ::clients::stateless::LibClient::new().build(req).unwrap();
        result.outputs.into_iter().next().unwrap()
    }
}
<|endoftext|>


<commit_before>fn main(){
    println!("cargo:rustc-link-lib=static=spsps");
    println!("cargo:rustc-link-search=native=./spsps/build");
    println!("cargo:libdir=./spsps/build");
}
<commit_msg>Updated build.rs to let cargo run anywhere in the directory tree<commit_after>use std::env;

fn main(){
    let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let spps_lib_dir = cargo_dir + "/spsps/build";
    println!("cargo:rustc-link-lib=static=spsps");
    println!("cargo:rustc-link-search=native={}", spps_lib_dir);
    println!("cargo:libdir=./spsps/build");
}
<|endoftext|>