<commit_before>use crate::utils::ptr::get_spans;
use crate::utils::{
    get_trait_def_id, implements_trait, is_copy, is_self, is_type_diagnostic_item, match_type, multispan_sugg, paths,
    snippet, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use matches::matches;
use rustc::traits;
use rustc::traits::misc::can_type_implement_copy;
use rustc::ty::{self, RegionKind, TypeFoldable};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{Span, Symbol};
use rustc_target::spec::abi::Abi;
use rustc_typeck::expr_use_visitor as euv;
use std::borrow::Cow;
use syntax::ast::Attribute;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, but not
    /// consuming them in its
    /// body.
    ///
    /// **Why is this bad?** Taking arguments by reference is more flexible and can
    /// sometimes avoid
    /// unnecessary allocations.
    ///
    /// **Known problems:**
    /// * This lint suggests taking an argument by reference,
    /// however sometimes it is better to let users decide the argument type
    /// (by using `Borrow` trait, for example), depending on how the function is used.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(v: Vec<i32>) {
    ///     assert_eq!(v.len(), 42);
    /// }
    /// ```
    ///
    /// ```rust
    /// // should be
    /// fn foo(v: &[i32]) {
    ///     assert_eq!(v.len(), 42);
    /// }
    /// ```
    pub NEEDLESS_PASS_BY_VALUE,
    pedantic,
    "functions taking arguments by value, but not consuming them in its body"
}

declare_lint_pass!(NeedlessPassByValue => [NEEDLESS_PASS_BY_VALUE]);

macro_rules! need {
    ($e: expr) => {
        if let Some(x) = $e {
            x
        } else {
            return;
        }
    };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    #[allow(clippy::too_many_lines)]
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                    return;
                }
            },
            FnKind::Method(..) => (),
            _ => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } |
                ItemKind::Trait(..))
            {
                return;
            }
        }

        // Allow `Borrow` or functions to be taken by value
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
        let whitelisted_traits = [
            need!(cx.tcx.lang_items().fn_trait()),
            need!(cx.tcx.lang_items().fn_once_trait()),
            need!(cx.tcx.lang_items().fn_mut_trait()),
            need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
        ];

        let sized_trait = need!(cx.tcx.lang_items().sized_trait());

        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
            .filter(|p| !p.is_global())
            .filter_map(|pred| {
                if let ty::Predicate::Trait(poly_trait_ref, _) = pred {
                    if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
                    {
                        return None;
                    }
                    Some(poly_trait_ref)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::default();
            cx.tcx.infer_ctxt().enter(|infcx| {
                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
            });
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            if span == input.span {
                return;
            }

            // Ignore `self`s.
            if idx == 0 {
                if let PatKind::Binding(.., ident, _) = arg.pat.kind {
                    if ident.as_str() == "self" {
                        continue;
                    }
                }
            }

            //
            // * Exclude a type that is specifically bounded by `Borrow`.
            // * Exclude a type whose reference also fulfills its bound. (e.g., `std::convert::AsRef`,
            //   `serde::Serialize`)
            let (implements_borrow_trait, all_borrowable_trait) = {
                let preds = preds
                    .iter()
                    .filter(|t| t.skip_binder().self_ty() == ty)
                    .collect::<Vec<_>>();

                (
                    preds.iter().any(|t| t.def_id() == borrow_trait),
                    !preds.is_empty()
                        && preds.iter().all(|t| {
                            let ty_params = &t
                                .skip_binder()
                                .trait_ref
                                .substs
                                .iter()
                                .skip(1)
                                .cloned()
                                .collect::<Vec<_>>();
                            implements_trait(cx, cx.tcx.mk_imm_ref(&RegionKind::ReEmpty, ty), t.def_id(), ty_params)
                        }),
                )
            };

            if_chain! {
                if !is_self(arg);
                if !ty.is_mutable_ptr();
                if !is_copy(cx, ty);
                if !whitelisted_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
                if !implements_borrow_trait;
                if !all_borrowable_trait;

                if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
                if !moved_vars.contains(&canonical_id);
                then {
                    if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                        continue;
                    }

                    // Dereference suggestion
                    let sugg = |db: &mut DiagnosticBuilder<'_>| {
                        if let ty::Adt(def, ..) = ty.kind {
                            if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
                                if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() {
                                    db.span_help(span, "consider marking this type as `Copy`");
                                }
                            }
                        }

                        let deref_span = spans_need_deref.get(&canonical_id);
                        if_chain! {
                            if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type"));
                            if let Some(clone_spans) =
                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
                            if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind;
                            if let Some(elem_ty) = path.segments.iter()
                                .find(|seg| seg.ident.name == sym!(Vec))
                                .and_then(|ps| ps.args.as_ref())
                                .map(|params| params.args.iter().find_map(|arg| match arg {
                                    GenericArg::Type(ty) => Some(ty),
                                    _ => None,
                                }).unwrap());
                            then {
                                let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                                db.span_suggestion(
                                    input.span,
                                    "consider changing the type to",
                                    slice_ty,
                                    Applicability::Unspecified,
                                );

                                for (span, suggestion) in clone_spans {
                                    db.span_suggestion(
                                        span,
                                        &snippet_opt(cx, span)
                                            .map_or(
                                                "change the call to".into(),
                                                |x| Cow::from(format!("change `{}` to", x)),
                                            ),
                                        suggestion.into(),
                                        Applicability::Unspecified,
                                    );
                                }

                                // cannot be destructured, no need for `*` suggestion
                                assert!(deref_span.is_none());
                                return;
                            }
                        }

                        if match_type(cx, ty, &paths::STRING) {
                            if let Some(clone_spans) =
                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                                db.span_suggestion(
                                    input.span,
                                    "consider changing the type to",
                                    "&str".to_string(),
                                    Applicability::Unspecified,
                                );

                                for (span, suggestion) in clone_spans {
                                    db.span_suggestion(
                                        span,
                                        &snippet_opt(cx, span)
                                            .map_or(
                                                "change the call to".into(),
                                                |x| Cow::from(format!("change `{}` to", x))
                                            ),
                                        suggestion.into(),
                                        Applicability::Unspecified,
                                    );
                                }

                                assert!(deref_span.is_none());
                                return;
                            }
                        }

                        let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                        // Suggests adding `*` to dereference the added reference.
                        if let Some(deref_span) = deref_span {
                            spans.extend(
                                deref_span
                                    .iter()
                                    .cloned()
                                    .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))),
                            );
                            spans.sort_by_key(|&(span, _)| span);
                        }
                        multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                    };

                    span_lint_and_then(
                        cx,
                        NEEDLESS_PASS_BY_VALUE,
                        input.span,
                        "this argument is passed by value, but not consumed in the function body",
                        sugg,
                    );
                }
            }
        }
    }
}

/// Functions marked with these attributes must have the exact signature.
fn requires_exact_signature(attrs: &[Attribute]) -> bool {
    attrs.iter().any(|attr| {
        [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)]
            .iter()
            .any(|&allow| attr.check_name(allow))
    })
}

#[derive(Default)]
struct MovedVariablesCtxt {
    moved_vars: FxHashSet<HirId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional reference.
    spans_need_deref: FxHashMap<HirId, FxHashSet<Span>>,
}

impl MovedVariablesCtxt {
    fn move_common(&mut self, cmt: &euv::Place<'_>) {
        if let euv::PlaceBase::Local(vid) = cmt.base {
            self.moved_vars.insert(vid);
        }
    }
}

impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
    fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move = mode {
            self.move_common(cmt);
        }
    }

    fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {}

    fn mutate(&mut self, _: &euv::Place<'tcx>) {}
}
<commit_msg>Auto merge of #5149 - lzutao:rustup-65232, r=flip1995<commit_after>use crate::utils::ptr::get_spans;
use crate::utils::{
    get_trait_def_id, implements_trait, is_copy, is_self, is_type_diagnostic_item, match_type, multispan_sugg, paths,
    snippet, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use matches::matches;
use rustc::traits;
use rustc::traits::misc::can_type_implement_copy;
use rustc::ty::{self, RegionKind, TypeFoldable};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::intravisit::FnKind;
use rustc_hir::*;
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{Span, Symbol};
use rustc_target::spec::abi::Abi;
use rustc_typeck::expr_use_visitor as euv;
use std::borrow::Cow;
use syntax::ast::Attribute;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, but not
    /// consuming them in its
    /// body.
    ///
    /// **Why is this bad?** Taking arguments by reference is more flexible and can
    /// sometimes avoid
    /// unnecessary allocations.
    ///
    /// **Known problems:**
    /// * This lint suggests taking an argument by reference,
    /// however sometimes it is better to let users decide the argument type
    /// (by using `Borrow` trait, for example), depending on how the function is used.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(v: Vec<i32>) {
    ///     assert_eq!(v.len(), 42);
    /// }
    /// ```
    ///
    /// ```rust
    /// // should be
    /// fn foo(v: &[i32]) {
    ///     assert_eq!(v.len(), 42);
    /// }
    /// ```
    pub NEEDLESS_PASS_BY_VALUE,
    pedantic,
    "functions taking arguments by value, but not consuming them in its body"
}

declare_lint_pass!(NeedlessPassByValue => [NEEDLESS_PASS_BY_VALUE]);

macro_rules! need {
    ($e: expr) => {
        if let Some(x) = $e {
            x
        } else {
            return;
        }
    };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    #[allow(clippy::too_many_lines)]
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust || requires_exact_signature(attrs) {
                    return;
                }
            },
            FnKind::Method(..) => (),
            _ => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } |
                ItemKind::Trait(..))
            {
                return;
            }
        }

        // Allow `Borrow` or functions to be taken by value
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
        let whitelisted_traits = [
            need!(cx.tcx.lang_items().fn_trait()),
            need!(cx.tcx.lang_items().fn_once_trait()),
            need!(cx.tcx.lang_items().fn_mut_trait()),
            need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
        ];

        let sized_trait = need!(cx.tcx.lang_items().sized_trait());

        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
            .filter(|p| !p.is_global())
            .filter_map(|pred| {
                if let ty::Predicate::Trait(poly_trait_ref, _) = pred {
                    if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_bound_vars()
                    {
                        return None;
                    }
                    Some(poly_trait_ref)
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::default();
            cx.tcx.infer_ctxt().enter(|infcx| {
                euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.tables).consume_body(body);
            });
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            if span == input.span {
                return;
            }

            // Ignore `self`s.
            if idx == 0 {
                if let PatKind::Binding(.., ident, _) = arg.pat.kind {
                    if ident.as_str() == "self" {
                        continue;
                    }
                }
            }

            //
            // * Exclude a type that is specifically bounded by `Borrow`.
            // * Exclude a type whose reference also fulfills its bound. (e.g., `std::convert::AsRef`,
            //   `serde::Serialize`)
            let (implements_borrow_trait, all_borrowable_trait) = {
                let preds = preds
                    .iter()
                    .filter(|t| t.skip_binder().self_ty() == ty)
                    .collect::<Vec<_>>();

                (
                    preds.iter().any(|t| t.def_id() == borrow_trait),
                    !preds.is_empty() && {
                        let ty_empty_region = cx.tcx.mk_imm_ref(&RegionKind::ReEmpty(ty::UniverseIndex::ROOT), ty);
                        preds.iter().all(|t| {
                            let ty_params = &t
                                .skip_binder()
                                .trait_ref
                                .substs
                                .iter()
                                .skip(1)
                                .cloned()
                                .collect::<Vec<_>>();
                            implements_trait(cx, ty_empty_region, t.def_id(), ty_params)
                        })
                    },
                )
            };

            if_chain! {
                if !is_self(arg);
                if !ty.is_mutable_ptr();
                if !is_copy(cx, ty);
                if !whitelisted_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
                if !implements_borrow_trait;
                if !all_borrowable_trait;

                if let PatKind::Binding(mode, canonical_id, ..) = arg.pat.kind;
                if !moved_vars.contains(&canonical_id);
                then {
                    if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                        continue;
                    }

                    // Dereference suggestion
                    let sugg = |db: &mut DiagnosticBuilder<'_>| {
                        if let ty::Adt(def, ..) = ty.kind {
                            if let Some(span) = cx.tcx.hir().span_if_local(def.did) {
                                if can_type_implement_copy(cx.tcx, cx.param_env, ty).is_ok() {
                                    db.span_help(span, "consider marking this type as `Copy`");
                                }
                            }
                        }

                        let deref_span = spans_need_deref.get(&canonical_id);
                        if_chain! {
                            if is_type_diagnostic_item(cx, ty, Symbol::intern("vec_type"));
                            if let Some(clone_spans) =
                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]);
                            if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind;
                            if let Some(elem_ty) = path.segments.iter()
                                .find(|seg| seg.ident.name == sym!(Vec))
                                .and_then(|ps| ps.args.as_ref())
                                .map(|params| params.args.iter().find_map(|arg| match arg {
                                    GenericArg::Type(ty) => Some(ty),
                                    _ => None,
                                }).unwrap());
                            then {
                                let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                                db.span_suggestion(
                                    input.span,
                                    "consider changing the type to",
                                    slice_ty,
                                    Applicability::Unspecified,
                                );

                                for (span, suggestion) in clone_spans {
                                    db.span_suggestion(
                                        span,
                                        &snippet_opt(cx, span)
                                            .map_or(
                                                "change the call to".into(),
                                                |x| Cow::from(format!("change `{}` to", x)),
                                            ),
                                        suggestion.into(),
                                        Applicability::Unspecified,
                                    );
                                }

                                // cannot be destructured, no need for `*` suggestion
                                assert!(deref_span.is_none());
                                return;
                            }
                        }

                        if match_type(cx, ty, &paths::STRING) {
                            if let Some(clone_spans) =
                                get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                                db.span_suggestion(
                                    input.span,
                                    "consider changing the type to",
                                    "&str".to_string(),
                                    Applicability::Unspecified,
                                );

                                for (span, suggestion) in clone_spans {
                                    db.span_suggestion(
                                        span,
                                        &snippet_opt(cx, span)
                                            .map_or(
                                                "change the call to".into(),
                                                |x| Cow::from(format!("change `{}` to", x))
                                            ),
                                        suggestion.into(),
                                        Applicability::Unspecified,
                                    );
                                }

                                assert!(deref_span.is_none());
                                return;
                            }
                        }

                        let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                        // Suggests adding `*` to dereference the added reference.
                        if let Some(deref_span) = deref_span {
                            spans.extend(
                                deref_span
                                    .iter()
                                    .cloned()
                                    .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))),
                            );
                            spans.sort_by_key(|&(span, _)| span);
                        }
                        multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                    };

                    span_lint_and_then(
                        cx,
                        NEEDLESS_PASS_BY_VALUE,
                        input.span,
                        "this argument is passed by value, but not consumed in the function body",
                        sugg,
                    );
                }
            }
        }
    }
}

/// Functions marked with these attributes must have the exact signature.
fn requires_exact_signature(attrs: &[Attribute]) -> bool {
    attrs.iter().any(|attr| {
        [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)]
            .iter()
            .any(|&allow| attr.check_name(allow))
    })
}

#[derive(Default)]
struct MovedVariablesCtxt {
    moved_vars: FxHashSet<HirId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional reference.
    spans_need_deref: FxHashMap<HirId, FxHashSet<Span>>,
}

impl MovedVariablesCtxt {
    fn move_common(&mut self, cmt: &euv::Place<'_>) {
        if let euv::PlaceBase::Local(vid) = cmt.base {
            self.moved_vars.insert(vid);
        }
    }
}

impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt {
    fn consume(&mut self, cmt: &euv::Place<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move = mode {
            self.move_common(cmt);
        }
    }

    fn borrow(&mut self, _: &euv::Place<'tcx>, _: ty::BorrowKind) {}

    fn mutate(&mut self, _: &euv::Place<'tcx>) {}
}
<|endoftext|>


<commit_before>//! Bootstrap your application!
//!
//! This module is used to create an application with spectra. Its aim is to quickly setup a spectra
//! app so that you can start working on interesting things.
use clap::{App, Arg};
use luminance_glfw;
pub use luminance_glfw::{Device as DeviceTrait, GLFWDeviceError, Key, MouseButton, WindowDim, WindowOpt};
use std::thread;
use std::time::{Duration, Instant};

pub use sys::event::WindowEvent;

pub type Time = f64;

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  raw: luminance_glfw::GLFWDevice,
  /// Some kind of epoch start the application started at.
  start_time: Instant
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// > Note: see `bootstrap!` macro for a better usage.
  pub fn new(def_width: u32,
             def_height: u32,
             version: &str,
             author: &str,
             title: &str,
             win_opt: WindowOpt)
             -> Result<Self, GLFWDeviceError> {
    let options = App::new(title)
      .version(version)
      .author(author)
      .arg(Arg::with_name("width")
           .short("w")
           .long("width")
           .value_name("WIDTH")
           .help("Sets the width of the viewport used for render")
           .takes_value(true))
      .arg(Arg::with_name("height")
           .short("h")
           .long("height")
           .value_name("HEIGHT")
           .help("Sets the height of the viewport used for render")
           .takes_value(true))
      .arg(Arg::with_name("fullscreen")
           .short("f")
           .long("fullscreen")
           .value_name("FULLSCREEN")
           .help("Sets the viewport to be displayed in fullscreen mode")
           .takes_value(false))
      .get_matches();

    let width = options.value_of("width").map(|s| s.parse().unwrap_or(def_width)).unwrap_or(def_width);
    let height = options.value_of("height").map(|s| s.parse().unwrap_or(def_height)).unwrap_or(def_height);
    let fullscreen = options.is_present("fullscreen");

    // build the WindowDim
    let win_dim = if fullscreen {
      if options.is_present("width") && options.is_present("height") {
        WindowDim::FullscreenRestricted(width, height)
      } else {
        WindowDim::Fullscreen
      }
    } else {
      WindowDim::Windowed(width, height)
    };

    info!("{} starting", title);
    info!("window mode: {:?}", win_dim);
    info!("window options: {:?}", win_opt);

    let dev = luminance_glfw::GLFWDevice::new(win_dim, title, win_opt)?;

    info!("bootstrapping finished");

    Ok(Device {
      raw: dev,
      start_time: Instant::now()
    })
  }

  /// Size of the attached window.
  #[inline]
  pub fn size(&self) -> [u32; 2] {
    self.raw.size()
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Get the last event and pop it from the event queue. Supposed to be called in a loop.
  pub fn events<'a>(&'a mut self) -> impl Iterator<Item = WindowEvent> + 'a {
    self.raw.events().map(|(_, e)| e)
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    let t = self.time();

    self.raw.draw(|| {
      draw_frame(t);
    });

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

#[macro_export]
macro_rules! bootstrap {
  ($def_width:expr, $def_height:expr, $win_opt:expr) => {{
    $crate::sys::bootstrap::Device::new($def_width,
                                        $def_height,
                                        crate_version!(),
                                        crate_authors!(),
                                        crate_name!(),
                                        $win_opt)
  }}
}
<commit_msg>Fixed bootstrap::Device::events.<commit_after>//! Bootstrap your application!
//!
//! This module is used to create an application with spectra. Its aim is to quickly setup a spectra
//! app so that you can start working on interesting things.
use clap::{App, Arg};
use luminance_glfw;
pub use luminance_glfw::{Device as DeviceTrait, GLFWDeviceError, Key, MouseButton, WindowDim, WindowOpt};
use std::thread;
use std::time::{Duration, Instant};

pub use sys::event::WindowEvent;

pub type Time = f64;

/// Device object.
///
/// Upon bootstrapping, this type is created to add interaction and context handling.
pub struct Device {
  raw: luminance_glfw::GLFWDevice,
  /// Some kind of epoch start the application started at.
  start_time: Instant
}

impl Device {
  /// Entry point.
  ///
  /// This function is the first one you have to call before anything else related to this crate.
  ///
  /// > Note: see `bootstrap!` macro for a better usage.
  pub fn new(def_width: u32,
             def_height: u32,
             version: &str,
             author: &str,
             title: &str,
             win_opt: WindowOpt)
             -> Result<Self, GLFWDeviceError> {
    let options = App::new(title)
      .version(version)
      .author(author)
      .arg(Arg::with_name("width")
           .short("w")
           .long("width")
           .value_name("WIDTH")
           .help("Sets the width of the viewport used for render")
           .takes_value(true))
      .arg(Arg::with_name("height")
           .short("h")
           .long("height")
           .value_name("HEIGHT")
           .help("Sets the height of the viewport used for render")
           .takes_value(true))
      .arg(Arg::with_name("fullscreen")
           .short("f")
           .long("fullscreen")
           .value_name("FULLSCREEN")
           .help("Sets the viewport to be displayed in fullscreen mode")
           .takes_value(false))
      .get_matches();

    let width = options.value_of("width").map(|s| s.parse().unwrap_or(def_width)).unwrap_or(def_width);
    let height = options.value_of("height").map(|s| s.parse().unwrap_or(def_height)).unwrap_or(def_height);
    let fullscreen = options.is_present("fullscreen");

    // build the WindowDim
    let win_dim = if fullscreen {
      if options.is_present("width") && options.is_present("height") {
        WindowDim::FullscreenRestricted(width, height)
      } else {
        WindowDim::Fullscreen
      }
    } else {
      WindowDim::Windowed(width, height)
    };

    info!("{} starting", title);
    info!("window mode: {:?}", win_dim);
    info!("window options: {:?}", win_opt);

    let dev = luminance_glfw::GLFWDevice::new(win_dim, title, win_opt)?;

    info!("bootstrapping finished");

    Ok(Device {
      raw: dev,
      start_time: Instant::now()
    })
  }

  /// Size of the attached window.
  #[inline]
  pub fn size(&self) -> [u32; 2] {
    self.raw.size()
  }

  /// Current time, starting from the beginning of the creation of that object.
  pub fn time(&self) -> f64 {
    let elapsed = Instant::now() - self.start_time;
    elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
  }

  /// Get the last event and pop it from the event queue. Supposed to be called in a loop.
  pub fn events<'a>(&'a mut self) -> impl Iterator<Item = WindowEvent> + 'a {
    self.raw.events()
  }

  /// Step function.
  ///
  /// This function provides two features:
  ///
  /// - it runs a *drawer* function, responsible of rendering a single frame, by passing it the
  ///   current time
  /// - it performs process idleing if you have requested a certain *framerate* – frame per second.
  ///
  /// The second feature is very neat because it lets you handle the scheduler off your application
  /// and then contribute to better CPU usage.
  ///
  /// > Note: if you pass `None`, no idleing will take place. However, you might be blocked by the
  /// *VSync* if enabled in your driver.
  pub fn step<FPS, R>(&mut self, fps: FPS, mut draw_frame: R) -> bool where FPS: Into<Option<u32>>, R: FnMut(Time) {
    let t = self.time();

    self.raw.draw(|| {
      draw_frame(t);
    });

    // wait for next frame according to the wished FPS
    if let Some(fps) = fps.into() {
      let fps = fps as f64;
      let max_time = 1. / fps;
      let elapsed_time = self.time() - t;

      if elapsed_time < max_time {
        let sleep_time = max_time - elapsed_time;
        thread::sleep(Duration::from_millis((sleep_time * 1e3) as u64));
      }
    }

    true
  }
}

#[macro_export]
macro_rules! bootstrap {
  ($def_width:expr, $def_height:expr, $win_opt:expr) => {{
    $crate::sys::bootstrap::Device::new($def_width,
                                        $def_height,
                                        crate_version!(),
                                        crate_authors!(),
                                        crate_name!(),
                                        $win_opt)
  }}
}
<|endoftext|>


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

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged : TaggedStream<char, SomeTag> = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;
use std::ops::Range;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    /// An untagged element in this stream
    Untagged(Base),

    /// A tagged region of the stream
    Tagged(Tag, TaggedStream<Base, Tag>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }

    ///
    /// Replaces a range in this stream with a tag
    ///
    pub fn tag(&mut self, tag: Tag, range: Range<usize>) {
        // Create a tag to replace the range
        let replaced_symbols    = self.data[range.clone()].to_vec();
        let tag_symbol          = TagSymbol::Tagged(tag, TaggedStream { data: replaced_symbols });

        // Draining seems to be for reading a range but does double duty for deleting a range?
        // I don't think rust has a way to replace a range in a vector, or at least not one that's easy to find in the docs.
        self.data.drain(range.clone());

        // Draining then inserting is inefficient compared to flat out replacing items :-/ This may be possible but the vec docs aren't very easy to read
        self.data.insert(range.start, tag_symbol);
    }

    ///
    /// Creates a tag symbol by tagging a particular range within this stream
    ///
    pub fn tag_range(&self, range: Range<usize>, tag: Tag) -> TagSymbol<Base, Tag> {
        let tag_data = self.data[range].to_vec();

        TagSymbol::Tagged(tag, TaggedStream { data: tag_data })
    }

    ///
    /// Applies tags to the specified ranges in this stream
    ///
    /// The tag ranges must be in ascending order and must not overlap
    ///
    pub fn with_tags(&self, tags: &Vec<(Range<usize>, Tag)>) -> TaggedStream<Base, Tag> {
        // The data that will make up the new stream
        let mut new_stream = vec![];

        // The last processed range (we haven't processed any range yet, so this starts at 0..0)
        let mut last_range = 0..0;

        // Build up the result from the tag list and the last range
        for tag in tags {
            // Fetch the information for this tag and check ordering
            let &(ref next_range, ref next_tag) = tag;
            let end                     = last_range.end;

            if end > next_range.start {
                panic!("Tags for with_tags must be sorted in order");
            }

            // Sometimes need to leave some data from this stream untagged
            if end < next_range.start {
                new_stream.extend(self.data[end..next_range.start].iter().cloned());
            }

            // Push the tag
            new_stream.push(self.tag_range(next_range.clone(), next_tag.clone()));

            // Update state
            last_range = next_range.clone();
        }

        // Append anything left in the stream
        if last_range.end < self.data.len() {
            new_stream.extend(self.data[last_range.end..self.data.len()].iter().cloned());
        }

        // Final result
        TaggedStream { data: new_stream }
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}

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

    #[test]
    fn can_tag_range() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let mut tagged: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());

        tagged.tag(Tags::Hello, 0..5);
        tagged.tag(Tags::World, 1..6);

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_tag_everything_with_tags() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(&vec![(0..5, Tags::Hello), (5..10, Tags::World)]);

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_middle() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(&vec![(0..4, Tags::Hello), (6..10, Tags::World)]);

        assert!(tagged.len() == 4);
        assert!(tagged[1] == TagSymbol::Untagged('o'));
        assert!(tagged[2] == TagSymbol::Untagged('W'));

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[3] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('o'));
            assert!(stream[1] == TagSymbol::Untagged('r'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_end() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(&vec![(0..5, Tags::Hello)]);

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        assert!(tagged[1] == TagSymbol::Untagged('W'));
        assert!(tagged[2] == TagSymbol::Untagged('o'));
        assert!(tagged[3] == TagSymbol::Untagged('r'));
        assert!(tagged[4] == TagSymbol::Untagged('l'));
        assert!(tagged[5] == TagSymbol::Untagged('d'));
    }

    #[test]
    fn with_tags_preserves_start() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(&vec![(5..10, Tags::World)]);

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[5] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }

        assert!(tagged[0] == TagSymbol::Untagged('H'));
        assert!(tagged[1] == TagSymbol::Untagged('e'));
        assert!(tagged[2] == TagSymbol::Untagged('l'));
        assert!(tagged[3] == TagSymbol::Untagged('l'));
        assert!(tagged[4] == TagSymbol::Untagged('o'));
    }
}
<commit_msg>Change with_tags to work with an iterator<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Tagged stream
//!
//! A tagged stream recursively applies tags to regions of an input stream. A stream consisting of a single tag forms a tree,
//! so this stream type is useful for representing the parsed represention of an input.
//!
//! The simplest form of tagged stream is one that's just a set of untagged symbols. This can be created using the `TaggedStream::from_reader`
//! method.
//!
//! ```
//! # use concordance::*;
//! #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
//! enum SomeTag {
//!     Identifier
//! };
//!
//! let simple_tagged : TaggedStream<char, SomeTag> = TaggedStream::from_reader(&mut "Hello, world".read_symbols());
//! ```
//!

use std::slice::Iter;
use std::ops::Index;
use std::ops::Range;

use super::symbol_reader::*;

///
/// Represents a symbol in a tagged stream.
///
/// A symbol can either be a sequence of untagged base symbols, or it can be a tag (which itself can contain any number of tagged symbol)
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TagSymbol<Base: Clone, Tag: Clone> {
    /// An untagged element in this stream
    Untagged(Base),

    /// A tagged region of the stream
    Tagged(Tag, TaggedStream<Base, Tag>)
}

///
/// Represents a stream of tagged symbols
///
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct TaggedStream<Base: Clone, Tag: Clone> {
    /// The data in this stream
    data: Vec<TagSymbol<Base, Tag>>
}

impl<Base: Clone, Tag: Clone> TaggedStream<Base, Tag> {
    ///
    /// Creates a basic tagged stream from a source of the base symbol
    ///
    pub fn from_reader(reader: &mut SymbolReader<Base>) -> TaggedStream<Base, Tag> {
        // Read from the reader into an array
        let mut symbols = vec![];

        while let Some(next_symbol) = reader.next_symbol() {
            symbols.push(TagSymbol::Untagged(next_symbol));
        }

        // Generate a simple tagged stream from the result
        TaggedStream { data: symbols }
    }

    ///
    /// The number of symbols in this stream
    ///
    pub fn len(&self) -> usize {
        self.data.len()
    }

    ///
    /// Replaces a range in this stream with a tag
    ///
    pub fn tag(&mut self, tag: Tag, range: Range<usize>) {
        // Create a tag to replace the range
        let replaced_symbols    = self.data[range.clone()].to_vec();
        let tag_symbol          = TagSymbol::Tagged(tag, TaggedStream { data: replaced_symbols });

        // Draining seems to be for reading a range but does double duty for deleting a range?
        // I don't think rust has a way to replace a range in a vector, or at least not one that's easy to find in the docs.
        self.data.drain(range.clone());

        // Draining then inserting is inefficient compared to flat out replacing items :-/ This may be possible but the vec docs aren't very easy to read
        self.data.insert(range.start, tag_symbol);
    }

    ///
    /// Creates a tag symbol by tagging a particular range within this stream
    ///
    pub fn tag_range(&self, range: Range<usize>, tag: Tag) -> TagSymbol<Base, Tag> {
        let tag_data = self.data[range].to_vec();

        TagSymbol::Tagged(tag, TaggedStream { data: tag_data })
    }

    ///
    /// Applies tags to the specified ranges in this stream
    ///
    /// The tag ranges must be in ascending order and must not overlap
    ///
    pub fn with_tags<I>(&self, tags: I) -> TaggedStream<Base, Tag>
        where I : Iterator<Item=(Range<usize>, Tag)> {
        // The data that will make up the new stream
        let mut new_stream = vec![];

        // The last processed range (we haven't processed any range yet, so this starts at 0..0)
        let mut last_range = 0..0;

        // Build up the result from the tag list and the last range
        for tag in tags {
            // Fetch the information for this tag and check ordering
            let (next_range, next_tag)  = tag;
            let end                     = last_range.end;

            if end > next_range.start {
                panic!("Tags for with_tags must be sorted in order");
            }

            // Sometimes need to leave some data from this stream untagged
            if end < next_range.start {
                new_stream.extend(self.data[end..next_range.start].iter().cloned());
            }

            // Push the tag
            new_stream.push(self.tag_range(next_range.clone(), next_tag));

            // Update state
            last_range = next_range;
        }

        // Append anything left in the stream
        if last_range.end < self.data.len() {
            new_stream.extend(self.data[last_range.end..self.data.len()].iter().cloned());
        }

        // Final result
        TaggedStream { data: new_stream }
    }
}

impl<Base: Clone, Tag: Clone> Index<usize> for TaggedStream<Base, Tag> {
    type Output = TagSymbol<Base, Tag>;

    fn index(&self, index: usize) -> &TagSymbol<Base, Tag> {
        &self.data[index]
    }
}

impl<'a, Base: Clone, Tag: Clone> SymbolSource<'a, TagSymbol<Base, Tag>> for &'a TaggedStream<Base, Tag> {
    type SymbolReader = Iter<'a, TagSymbol<Base, Tag>>;

    /// Returns a new object that can read the symbols from this one
    fn read_symbols(self) -> Self::SymbolReader {
        self.data.read_symbols()
    }
}

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

    #[test]
    fn can_tag_range() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let mut tagged: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());

        tagged.tag(Tags::Hello, 0..5);
        tagged.tag(Tags::World, 1..6);

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn can_tag_everything_with_tags() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello), (5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 2);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[1] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_middle() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello,
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..4, Tags::Hello), (6..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 4);
        assert!(tagged[1] == TagSymbol::Untagged('o'));
        assert!(tagged[2] == TagSymbol::Untagged('W'));

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
        } else {
            assert!(false);
        }

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[3] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 4);
            assert!(stream[0] == TagSymbol::Untagged('o'));
            assert!(stream[1] == TagSymbol::Untagged('r'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }
    }

    #[test]
    fn with_tags_preserves_end() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            Hello
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(0..5, Tags::Hello)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[0] {
            assert!(*tag == Tags::Hello);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('H'));
            assert!(stream[1] == TagSymbol::Untagged('e'));
            assert!(stream[2] == TagSymbol::Untagged('l'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('o'));
        } else {
            assert!(false);
        }

        assert!(tagged[1] == TagSymbol::Untagged('W'));
        assert!(tagged[2] == TagSymbol::Untagged('o'));
        assert!(tagged[3] == TagSymbol::Untagged('r'));
        assert!(tagged[4] == TagSymbol::Untagged('l'));
        assert!(tagged[5] == TagSymbol::Untagged('d'));
    }

    #[test]
    fn with_tags_preserves_start() {
        #[derive(Clone, PartialEq, Eq, Copy)]
        enum Tags {
            World
        }

        let original: TaggedStream<char, Tags> = TaggedStream::from_reader(&mut "HelloWorld".read_symbols());
        let tagged = original.with_tags(vec![(5..10, Tags::World)].iter().cloned());

        assert!(tagged.len() == 6);

        if let TagSymbol::Tagged(ref tag, ref stream) = tagged[5] {
            assert!(*tag == Tags::World);
            assert!(stream.len() == 5);
            assert!(stream[0] == TagSymbol::Untagged('W'));
            assert!(stream[1] == TagSymbol::Untagged('o'));
            assert!(stream[2] == TagSymbol::Untagged('r'));
            assert!(stream[3] == TagSymbol::Untagged('l'));
            assert!(stream[4] == TagSymbol::Untagged('d'));
        } else {
            assert!(false);
        }

        assert!(tagged[0] == TagSymbol::Untagged('H'));
        assert!(tagged[1] == TagSymbol::Untagged('e'));
        assert!(tagged[2] == TagSymbol::Untagged('l'));
        assert!(tagged[3] == TagSymbol::Untagged('l'));
        assert!(tagged[4] == TagSymbol::Untagged('o'));
    }
}
<|endoftext|>


<commit_before>use super::wasm;
use anyhow::Context;
use std::env;
use std::fs;
use std::net::TcpListener;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use tiny_http::{Header, Response, Server};
use webbrowser;

macro_rules! resource {
    ($name: tt, $path: tt) => {
        #[cfg(TREE_SITTER_EMBED_WASM_BINDING)]
        fn $name(tree_sitter_dir: &Option<PathBuf>) -> Vec<u8> {
            if let Some(tree_sitter_dir) = tree_sitter_dir {
                fs::read(tree_sitter_dir.join($path)).unwrap()
            } else {
                include_bytes!(concat!("../../", $path)).to_vec()
            }
        }

        #[cfg(not(TREE_SITTER_EMBED_WASM_BINDING))]
        fn $name(tree_sitter_dir: &Option<PathBuf>) -> Vec<u8> {
            if let Some(tree_sitter_dir) = tree_sitter_dir {
                fs::read(tree_sitter_dir.join($path)).unwrap()
            } else {
                Vec::new()
            }
        }
    };
}

resource!(get_main_html, "cli/src/web_ui.html");
resource!(get_playground_js, "docs/assets/js/playground.js");
resource!(get_lib_js, "lib/binding_web/tree-sitter.js");
resource!(get_lib_wasm, "lib/binding_web/tree-sitter.wasm");

pub fn serve(grammar_path: &Path, open_in_browser: bool) {
    let port = get_available_port().expect("Couldn't find an available port");
    let url = format!("127.0.0.1:{}", port);
    let server = Server::http(&url).expect("Failed to start web server");
    let grammar_name = wasm::get_grammar_name(&grammar_path.join("src"))
        .with_context(|| "Failed to get wasm filename")
        .unwrap();
    let wasm_filename = format!("tree-sitter-{}.wasm", grammar_name);
    let language_wasm = fs::read(grammar_path.join(&wasm_filename))
        .with_context(|| {
            format!(
                "Failed to read {}. Run `tree-sitter build-wasm` first.",
                wasm_filename
            )
        })
        .unwrap();
    println!("Started playground on '{}'", url);
    if open_in_browser {
        if let Err(_) = webbrowser::open(&url) {
            eprintln!("Failed to open '{}' in a web browser", url);
        }
    }

    let tree_sitter_dir = env::var("TREE_SITTER_BASE_DIR").map(PathBuf::from).ok();
    let main_html = String::from_utf8(get_main_html(&tree_sitter_dir))
        .unwrap()
        .replace("THE_LANGUAGE_NAME", &grammar_name)
        .into_bytes();
    let playground_js = get_playground_js(&tree_sitter_dir);
    let lib_js = get_lib_js(&tree_sitter_dir);
    let lib_wasm = get_lib_wasm(&tree_sitter_dir);

    let html_header = Header::from_str("Content-Type: text/html").unwrap();
    let js_header = Header::from_str("Content-Type: application/javascript").unwrap();
    let wasm_header = Header::from_str("Content-Type: application/wasm").unwrap();

    for request in server.incoming_requests() {
        let res = match request.url() {
            "/" => response(&main_html, &html_header),
            "/tree-sitter-parser.wasm" => response(&language_wasm, &wasm_header),
            "/playground.js" => {
                if playground_js.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter/assets/js/playground.js")
                } else {
                    response(&playground_js, &js_header)
                }
            }
            "/tree-sitter.js" => {
                if lib_js.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter.js")
                } else {
                    response(&lib_js, &js_header)
                }
            }
            "/tree-sitter.wasm" => {
                if lib_wasm.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter.wasm")
                } else {
                    response(&lib_wasm, &wasm_header)
                }
            }
            _ => response(b"Not found", &html_header).with_status_code(404),
        };
        request.respond(res).expect("Failed to write HTTP response");
    }
}

fn redirect<'a>(url: &'a str) -> Response<&'a [u8]> {
    Response::empty(302)
        .with_data("".as_bytes(), Some(0))
        .with_header(Header::from_bytes("Location", url.as_bytes()).unwrap())
}

fn response<'a>(data: &'a [u8], header: &Header) -> Response<&'a [u8]> {
    Response::empty(200)
        .with_data(data, Some(data.len()))
        .with_header(header.clone())
}

fn get_available_port() -> Option<u16> {
    (8000..12000).find(port_is_available)
}

fn port_is_available(port: &u16) -> bool {
    TcpListener::bind(("127.0.0.1", *port)).is_ok()
}
<commit_msg>fix(cli): Fix playground opening in a browser, regression in #1304<commit_after>use super::wasm;
use anyhow::Context;
use std::env;
use std::fs;
use std::net::TcpListener;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use tiny_http::{Header, Response, Server};
use webbrowser;

macro_rules! resource {
    ($name: tt, $path: tt) => {
        #[cfg(TREE_SITTER_EMBED_WASM_BINDING)]
        fn $name(tree_sitter_dir: &Option<PathBuf>) -> Vec<u8> {
            if let Some(tree_sitter_dir) = tree_sitter_dir {
                fs::read(tree_sitter_dir.join($path)).unwrap()
            } else {
                include_bytes!(concat!("../../", $path)).to_vec()
            }
        }

        #[cfg(not(TREE_SITTER_EMBED_WASM_BINDING))]
        fn $name(tree_sitter_dir: &Option<PathBuf>) -> Vec<u8> {
            if let Some(tree_sitter_dir) = tree_sitter_dir {
                fs::read(tree_sitter_dir.join($path)).unwrap()
            } else {
                Vec::new()
            }
        }
    };
}

resource!(get_main_html, "cli/src/web_ui.html");
resource!(get_playground_js, "docs/assets/js/playground.js");
resource!(get_lib_js, "lib/binding_web/tree-sitter.js");
resource!(get_lib_wasm, "lib/binding_web/tree-sitter.wasm");

pub fn serve(grammar_path: &Path, open_in_browser: bool) {
    let port = get_available_port().expect("Couldn't find an available port");
    let addr = format!("127.0.0.1:{}", port);
    let server = Server::http(&addr).expect("Failed to start web server");
    let grammar_name = wasm::get_grammar_name(&grammar_path.join("src"))
        .with_context(|| "Failed to get wasm filename")
        .unwrap();
    let wasm_filename = format!("tree-sitter-{}.wasm", grammar_name);
    let language_wasm = fs::read(grammar_path.join(&wasm_filename))
        .with_context(|| {
            format!(
                "Failed to read {}. Run `tree-sitter build-wasm` first.",
                wasm_filename
            )
        })
        .unwrap();
    let url = format!("http://{}", addr);
    println!("Started playground on: {}", url);
    if open_in_browser {
        if let Err(_) = webbrowser::open(&url) {
            eprintln!("Failed to open '{}' in a web browser", url);
        }
    }

    let tree_sitter_dir = env::var("TREE_SITTER_BASE_DIR").map(PathBuf::from).ok();
    let main_html = String::from_utf8(get_main_html(&tree_sitter_dir))
        .unwrap()
        .replace("THE_LANGUAGE_NAME", &grammar_name)
        .into_bytes();
    let playground_js = get_playground_js(&tree_sitter_dir);
    let lib_js = get_lib_js(&tree_sitter_dir);
    let lib_wasm = get_lib_wasm(&tree_sitter_dir);

    let html_header = Header::from_str("Content-Type: text/html").unwrap();
    let js_header = Header::from_str("Content-Type: application/javascript").unwrap();
    let wasm_header = Header::from_str("Content-Type: application/wasm").unwrap();

    for request in server.incoming_requests() {
        let res = match request.url() {
            "/" => response(&main_html, &html_header),
            "/tree-sitter-parser.wasm" => response(&language_wasm, &wasm_header),
            "/playground.js" => {
                if playground_js.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter/assets/js/playground.js")
                } else {
                    response(&playground_js, &js_header)
                }
            }
            "/tree-sitter.js" => {
                if lib_js.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter.js")
                } else {
                    response(&lib_js, &js_header)
                }
            }
            "/tree-sitter.wasm" => {
                if lib_wasm.is_empty() {
                    redirect("https://tree-sitter.github.io/tree-sitter.wasm")
                } else {
                    response(&lib_wasm, &wasm_header)
                }
            }
            _ => response(b"Not found", &html_header).with_status_code(404),
        };
        request.respond(res).expect("Failed to write HTTP response");
    }
}

fn redirect<'a>(url: &'a str) -> Response<&'a [u8]> {
    Response::empty(302)
        .with_data("".as_bytes(), Some(0))
        .with_header(Header::from_bytes("Location", url.as_bytes()).unwrap())
}

fn response<'a>(data: &'a [u8], header: &Header) -> Response<&'a [u8]> {
    Response::empty(200)
        .with_data(data, Some(data.len()))
        .with_header(header.clone())
}

fn get_available_port() -> Option<u16> {
    (8000..12000).find(port_is_available)
}

fn port_is_available(port: &u16) -> bool {
    TcpListener::bind(("127.0.0.1", *port)).is_ok()
}
<|endoftext|>


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

use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
use crate::StreamId;
use serde_json::{Map, Value};
use std::net::TcpStream;

pub struct PreferenceActor {
    name: String,
}

impl PreferenceActor {
    pub fn new(name: String) -> Self {
        Self { name }
    }
}

impl Actor for PreferenceActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(
        &self,
        _registry: &ActorRegistry,
        msg_type: &str,
        _msg: &Map<String, Value>,
        stream: &mut TcpStream,
        _id: StreamId,
    ) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "getBoolPref" => {
                let reply = BoolReply {
                    from: self.name(),
                    value: false,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },

            "getCharPref" => {
                let reply = CharReply {
                    from: self.name(),
                    value: "".to_owned(),
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },

            "getIntPref" => {
                let reply = IntReply {
                    from: self.name(),
                    value: 0,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },

            _ => ActorMessageStatus::Ignored,
        })
    }
}

#[derive(Serialize)]
struct BoolReply {
    from: String,
    value: bool,
}

#[derive(Serialize)]
struct CharReply {
    from: String,
    value: String,
}

#[derive(Serialize)]
struct IntReply {
    from: String,
    value: i32,
}
<commit_msg>Auto merge of #27634 - sudarshan-reddy:preferences-actor-returns-real-vals, r=jdm<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/. */

use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::protocol::JsonPacketStream;
use crate::StreamId;
use serde_json::{Map, Value};
use servo_config::pref_util::PrefValue;
use servo_config::prefs::pref_map;
use std::net::TcpStream;

pub struct PreferenceActor {
    name: String,
}

impl PreferenceActor {
    pub fn new(name: String) -> Self {
        Self { name }
    }
}

impl Actor for PreferenceActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(
        &self,
        _registry: &ActorRegistry,
        msg_type: &str,
        _msg: &Map<String, Value>,
        stream: &mut TcpStream,
        _id: StreamId,
    ) -> Result<ActorMessageStatus, ()> {
        let pref_value = pref_map().get(msg_type);
        Ok(match pref_value {
            PrefValue::Float(value) => {
                let reply = FloatReply {
                    from: self.name(),
                    value: value,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },
            PrefValue::Int(value) => {
                let reply = IntReply {
                    from: self.name(),
                    value: value,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },
            PrefValue::Str(value) => {
                let reply = CharReply {
                    from: self.name(),
                    value: value,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },
            PrefValue::Bool(value) => {
                let reply = BoolReply {
                    from: self.name(),
                    value: value,
                };
                let _ = stream.write_json_packet(&reply);
                ActorMessageStatus::Processed
            },
            PrefValue::Missing => handle_missing_preference(self.name(), msg_type, stream),
        })
    }
}

// if the preferences are missing from pref_map then we return a
// fake preference response based on msg_type.
fn handle_missing_preference(
    name: String,
    msg_type: &str,
    stream: &mut TcpStream,
) -> ActorMessageStatus {
    match msg_type {
        "getBoolPref" => {
            let reply = BoolReply {
                from: name,
                value: false,
            };
            let _ = stream.write_json_packet(&reply);
            ActorMessageStatus::Processed
        },

        "getCharPref" => {
            let reply = CharReply {
                from: name,
                value: "".to_owned(),
            };
            let _ = stream.write_json_packet(&reply);
            ActorMessageStatus::Processed
        },

        "getIntPref" => {
            let reply = IntReply {
                from: name,
                value: 0,
            };
            let _ = stream.write_json_packet(&reply);
            ActorMessageStatus::Processed
        },

        _ => ActorMessageStatus::Ignored,
    }
}

#[derive(Serialize)]
struct BoolReply {
    from: String,
    value: bool,
}

#[derive(Serialize)]
struct CharReply {
    from: String,
    value: String,
}

#[derive(Serialize)]
struct IntReply {
    from: String,
    value: i64,
}

#[derive(Serialize)]
struct FloatReply {
    from: String,
    value: f64,
}
<|endoftext|>


<commit_before>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! You can find extensive tutorials and documentations at [https://tokio.rs]
//! for both this crate (asynchronous programming in general) as well as the
//! Tokio stack to perform async I/O with.
//!
//! [https://tokio.rs]: https://tokio.rs
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::prelude::*;
//! use futures::future::Map;
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `Box::new()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             Ok(result) => {
//!                 let (data, _other_future) = result.split();
//!                 match data {
//!                     // One future succeeded, and it was the one which was
//!                     // downloading data from the connection.
//!                     Ok(data) => Ok(data),
//!
//!                     // The timeout fired, and otherwise no error was found, so
//!                     // we translate this to an error.
//!                     Err(_timeout) => {
//!                         Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!                     }
//!                 }
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err(err) => Err(err.split().0),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![doc(html_root_url = "https://docs.rs/futures/0.2")]

extern crate futures_core;
extern crate futures_channel;
extern crate futures_executor;
extern crate futures_sink;
extern crate futures_util;

pub use futures_core::future::{Future, IntoFuture};
pub use futures_util::future::FutureExt;
pub use futures_core::stream::Stream;
pub use futures_util::stream::StreamExt;
pub use futures_sink::Sink;
pub use futures_util::sink::SinkExt;

// Macros redefined here because macro re-exports are unstable.

/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `Pending` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::prelude::Async::Ready(t)) => t,
        Ok($crate::prelude::Async::Pending) => return Ok($crate::prelude::Async::Pending),
        Err(e) => return Err(From::from(e)),
    })
}

// TODO: task_local macro

#[cfg(feature = "std")]
pub mod channel {
    //! Channels
    //!
    //! This module contains channels for asynchronous
    //! communication.
    pub use futures_channel::*;
}

pub mod executor {
    //! Executors
    //!
    //! This module contains the `Executor` trait, which allows futures to be
    //! spawned and executed asynchronously.

    pub use futures_executor::*;
    pub use futures_core::executor::*;
}

pub mod future {
    //! Futures
    //!
    //! This module contains the `Future` trait and adapters for this trait.

    pub use futures_core::future::*;
    pub use futures_util::future::*;
}

pub mod prelude {
	//! A "prelude" for crates using the `futures` crate.
	//!
	//! This prelude is similar to the standard library's prelude in that you'll
	//! almost always want to import its entire contents, but unlike the standard
	//! library's prelude you'll have to do so manually. An example of using this is:
	//!
	//! ```
	//! use futures::prelude::*;
	//! ```
	//!
	//! We may add items to this over time as they become ubiquitous as well, but
	//! otherwise this should help cut down on futures-related imports when you're
	//! working with the `futures` crate!

    pub use futures_core::{
        Future,
        IntoFuture,
        Stream,
        Async,
        Poll,
    };

    pub use futures_sink::{
        Sink,
        AsyncSink,
        StartSend,
    };

    pub use futures_util::{
		FutureExt,
		StreamExt,
        SinkExt,
    };
}

pub mod sink {
	//! Asynchronous sinks
	//!
	//! This module contains the `Sink` trait, along with a number of adapter types
	//! for it. An overview is available in the documentation for the trait itself.
	//!
	//! You can find more information/tutorials about streams [online at
	//! https://tokio.rs][online]
	//!
	//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

    pub use futures_sink::*;
    pub use futures_util::sink::*;
}

pub mod stream {
	//! Asynchronous streams
	//!
	//! This module contains the `Stream` trait and a number of adaptors for this
	//! trait. This trait is very similar to the `Iterator` trait in the standard
	//! library except that it expresses the concept of blocking as well. A stream
	//! here is a sequential sequence of values which may take some amount of time
	//! in between to produce.
	//!
	//! A stream may request that it is blocked between values while the next value
	//! is calculated, and provides a way to get notified once the next value is
	//! ready as well.
	//!
	//! You can find more information/tutorials about streams [online at
	//! https://tokio.rs][online]
	//!
	//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

    pub use futures_core::stream::*;
    pub use futures_util::stream::*;
}

pub mod task {
    //! Task executon
    pub use futures_core::task::*;
}
<commit_msg>Add Poll, Async export<commit_after>//! Zero-cost Futures in Rust
//!
//! This library is an implementation of futures in Rust which aims to provide
//! a robust implementation of handling asynchronous computations, ergonomic
//! composition and usage, and zero-cost abstractions over what would otherwise
//! be written by hand.
//!
//! Futures are a concept for an object which is a proxy for another value that
//! may not be ready yet. For example issuing an HTTP request may return a
//! future for the HTTP response, as it probably hasn't arrived yet. With an
//! object representing a value that will eventually be available, futures allow
//! for powerful composition of tasks through basic combinators that can perform
//! operations like chaining computations, changing the types of futures, or
//! waiting for two futures to complete at the same time.
//!
//! You can find extensive tutorials and documentations at [https://tokio.rs]
//! for both this crate (asynchronous programming in general) as well as the
//! Tokio stack to perform async I/O with.
//!
//! [https://tokio.rs]: https://tokio.rs
//!
//! ## Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! futures = "0.1"
//! ```
//!
//! ## Examples
//!
//! Let's take a look at a few examples of how futures might be used:
//!
//! ```
//! extern crate futures;
//!
//! use std::io;
//! use std::time::Duration;
//! use futures::prelude::*;
//! use futures::future::Map;
//!
//! // A future is actually a trait implementation, so we can generically take a
//! // future of any integer and return back a future that will resolve to that
//! // value plus 10 more.
//! //
//! // Note here that like iterators, we're returning the `Map` combinator in
//! // the futures crate, not a boxed abstraction. This is a zero-cost
//! // construction of a future.
//! fn add_ten<F>(future: F) -> Map<F, fn(i32) -> i32>
//!     where F: Future<Item=i32>,
//! {
//!     fn add(a: i32) -> i32 { a + 10 }
//!     future.map(add)
//! }
//!
//! // Not only can we modify one future, but we can even compose them together!
//! // Here we have a function which takes two futures as input, and returns a
//! // future that will calculate the sum of their two values.
//! //
//! // Above we saw a direct return value of the `Map` combinator, but
//! // performance isn't always critical and sometimes it's more ergonomic to
//! // return a trait object like we do here. Note though that there's only one
//! // allocation here, not any for the intermediate futures.
//! fn add<'a, A, B>(a: A, b: B) -> Box<Future<Item=i32, Error=A::Error> + 'a>
//!     where A: Future<Item=i32> + 'a,
//!           B: Future<Item=i32, Error=A::Error> + 'a,
//! {
//!     Box::new(a.join(b).map(|(a, b)| a + b))
//! }
//!
//! // Futures also allow chaining computations together, starting another after
//! // the previous finishes. Here we wait for the first computation to finish,
//! // and then decide what to do depending on the result.
//! fn download_timeout(url: &str,
//!                     timeout_dur: Duration)
//!                     -> Box<Future<Item=Vec<u8>, Error=io::Error>> {
//!     use std::io;
//!     use std::net::{SocketAddr, TcpStream};
//!
//!     type IoFuture<T> = Box<Future<Item=T, Error=io::Error>>;
//!
//!     // First thing to do is we need to resolve our URL to an address. This
//!     // will likely perform a DNS lookup which may take some time.
//!     let addr = resolve(url);
//!
//!     // After we acquire the address, we next want to open up a TCP
//!     // connection.
//!     let tcp = addr.and_then(|addr| connect(&addr));
//!
//!     // After the TCP connection is established and ready to go, we're off to
//!     // the races!
//!     let data = tcp.and_then(|conn| download(conn));
//!
//!     // That all might take awhile, though, so let's not wait too long for it
//!     // to all come back. The `select` combinator here returns a future which
//!     // resolves to the first value that's ready plus the next future.
//!     //
//!     // Note we can also use the `then` combinator which is similar to
//!     // `and_then` above except that it receives the result of the
//!     // computation, not just the successful value.
//!     //
//!     // Again note that all the above calls to `and_then` and the below calls
//!     // to `map` and such require no allocations. We only ever allocate once
//!     // we hit the `Box::new()` call at the end here, which means we've built
//!     // up a relatively involved computation with only one box, and even that
//!     // was optional!
//!
//!     let data = data.map(Ok);
//!     let timeout = timeout(timeout_dur).map(Err);
//!
//!     let ret = data.select(timeout).then(|result| {
//!         match result {
//!             Ok(result) => {
//!                 let (data, _other_future) = result.split();
//!                 match data {
//!                     // One future succeeded, and it was the one which was
//!                     // downloading data from the connection.
//!                     Ok(data) => Ok(data),
//!
//!                     // The timeout fired, and otherwise no error was found, so
//!                     // we translate this to an error.
//!                     Err(_timeout) => {
//!                         Err(io::Error::new(io::ErrorKind::Other, "timeout"))
//!                     }
//!                 }
//!             }
//!
//!             // A normal I/O error happened, so we pass that on through.
//!             Err(err) => Err(err.split().0),
//!         }
//!     });
//!     return Box::new(ret);
//!
//!     fn resolve(url: &str) -> IoFuture<SocketAddr> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn connect(hostname: &SocketAddr) -> IoFuture<TcpStream> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn download(stream: TcpStream) -> IoFuture<Vec<u8>> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//!
//!     fn timeout(stream: Duration) -> IoFuture<()> {
//!         // ...
//! #       panic!("unimplemented");
//!     }
//! }
//! # fn main() {}
//! ```
//!
//! Some more information can also be found in the [README] for now, but
//! otherwise feel free to jump in to the docs below!
//!
//! [README]: https://github.com/alexcrichton/futures-rs#futures-rs

#![no_std]
#![doc(html_root_url = "https://docs.rs/futures/0.2")]

extern crate futures_core;
extern crate futures_channel;
extern crate futures_executor;
extern crate futures_sink;
extern crate futures_util;

pub use futures_core::future::{Future, IntoFuture};
pub use futures_util::future::FutureExt;
pub use futures_core::stream::Stream;
pub use futures_util::stream::StreamExt;
pub use futures_sink::Sink;
pub use futures_util::sink::SinkExt;

// Macros redefined here because macro re-exports are unstable.

/// A macro for extracting the successful type of a `Poll<T, E>`.
///
/// This macro bakes propagation of both errors and `Pending` signals by
/// returning early.
#[macro_export]
macro_rules! try_ready {
    ($e:expr) => (match $e {
        Ok($crate::prelude::Async::Ready(t)) => t,
        Ok($crate::prelude::Async::Pending) => return Ok($crate::prelude::Async::Pending),
        Err(e) => return Err(From::from(e)),
    })
}

// TODO: task_local macro

pub use futures_core::{Async, Poll};

#[cfg(feature = "std")]
pub mod channel {
    //! Channels
    //!
    //! This module contains channels for asynchronous
    //! communication.
    pub use futures_channel::*;
}

pub mod executor {
    //! Executors
    //!
    //! This module contains the `Executor` trait, which allows futures to be
    //! spawned and executed asynchronously.

    pub use futures_executor::*;
    pub use futures_core::executor::*;
}

pub mod future {
    //! Futures
    //!
    //! This module contains the `Future` trait and adapters for this trait.

    pub use futures_core::future::*;
    pub use futures_util::future::*;
}

pub mod prelude {
	//! A "prelude" for crates using the `futures` crate.
	//!
	//! This prelude is similar to the standard library's prelude in that you'll
	//! almost always want to import its entire contents, but unlike the standard
	//! library's prelude you'll have to do so manually. An example of using this is:
	//!
	//! ```
	//! use futures::prelude::*;
	//! ```
	//!
	//! We may add items to this over time as they become ubiquitous as well, but
	//! otherwise this should help cut down on futures-related imports when you're
	//! working with the `futures` crate!

    pub use futures_core::{
        Future,
        IntoFuture,
        Stream,
        Async,
        Poll,
    };

    pub use futures_sink::{
        Sink,
        AsyncSink,
        StartSend,
    };

    pub use futures_util::{
		FutureExt,
		StreamExt,
        SinkExt,
    };
}

pub mod sink {
	//! Asynchronous sinks
	//!
	//! This module contains the `Sink` trait, along with a number of adapter types
	//! for it. An overview is available in the documentation for the trait itself.
	//!
	//! You can find more information/tutorials about streams [online at
	//! https://tokio.rs][online]
	//!
	//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

    pub use futures_sink::*;
    pub use futures_util::sink::*;
}

pub mod stream {
	//! Asynchronous streams
	//!
	//! This module contains the `Stream` trait and a number of adaptors for this
	//! trait. This trait is very similar to the `Iterator` trait in the standard
	//! library except that it expresses the concept of blocking as well. A stream
	//! here is a sequential sequence of values which may take some amount of time
	//! in between to produce.
	//!
	//! A stream may request that it is blocked between values while the next value
	//! is calculated, and provides a way to get notified once the next value is
	//! ready as well.
	//!
	//! You can find more information/tutorials about streams [online at
	//! https://tokio.rs][online]
	//!
	//! [online]: https://tokio.rs/docs/getting-started/streams-and-sinks/

    pub use futures_core::stream::*;
    pub use futures_util::stream::*;
}

pub mod task {
    //! Task executon
    pub use futures_core::task::*;
}
<|endoftext|>