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

use abi::Abi;
use common::*;

use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::DropInPlaceFnLangItem;
use rustc::traits;
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};

use syntax::codemap::DUMMY_SP;

pub use rustc::ty::Instance;

fn fn_once_adapter_instance<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    closure_did: DefId,
    substs: ty::ClosureSubsts<'tcx>,
    ) -> Instance<'tcx> {
    debug!("fn_once_adapter_shim({:?}, {:?})",
           closure_did,
           substs);
    let fn_once = tcx.lang_items().fn_once_trait().unwrap();
    let call_once = tcx.associated_items(fn_once)
        .find(|it| it.kind == ty::AssociatedKind::Method)
        .unwrap().def_id;
    let def = ty::InstanceDef::ClosureOnceShim { call_once };

    let self_ty = tcx.mk_closure_from_closure_substs(
        closure_did, substs);

    let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs);
    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
    assert_eq!(sig.inputs().len(), 1);
    let substs = tcx.mk_substs([
        Kind::from(self_ty),
        Kind::from(sig.inputs()[0]),
    ].iter().cloned());

    debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
    Instance { def, substs }
}

fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
                              trait_closure_kind: ty::ClosureKind)
                              -> Result<bool, ()>
{
    match (actual_closure_kind, trait_closure_kind) {
        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
            // No adapter needed.
           Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
            // `fn(&mut self, ...)`. In fact, at trans time, these are
            // basically the same thing, so we can just return llfn.
            Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
            // self, ...)`.  We want a `fn(self, ...)`. We can produce
            // this by doing something like:
            //
            //     fn call_once(self, ...) { call_mut(&self, ...) }
            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
            //
            // These are both the same at trans time.
            Ok(true)
        }
        _ => Err(()),
    }
}

pub fn resolve_closure<'a, 'tcx> (
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    substs: ty::ClosureSubsts<'tcx>,
    requested_kind: ty::ClosureKind)
    -> Instance<'tcx>
{
    let actual_kind = tcx.closure_kind(def_id);

    match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
        Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
        _ => Instance::new(def_id, substs.substs)
    }
}

fn resolve_associated_item<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    trait_item: &ty::AssociatedItem,
    trait_id: DefId,
    rcvr_substs: &'tcx Substs<'tcx>
) -> Instance<'tcx> {
    let def_id = trait_item.def_id;
    debug!("resolve_associated_item(trait_item={:?}, \
                                    trait_id={:?}, \
                                    rcvr_substs={:?})",
           def_id, trait_id, rcvr_substs);

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref));

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            let (def_id, substs) = traits::find_associated_item(
                tcx, trait_item, rcvr_substs, &impl_data);
            let substs = tcx.erase_regions(&substs);
            ty::Instance::new(def_id, substs)
        }
        traits::VtableGenerator(closure_data) => {
            Instance {
                def: ty::InstanceDef::Item(closure_data.closure_def_id),
                substs: closure_data.substs.substs
            }
        }
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
            resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                            trait_closure_kind)
        }
        traits::VtableFnPointer(ref data) => {
            Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs
            }
        }
        traits::VtableObject(ref data) => {
            let index = tcx.get_vtable_index_of_object_method(data, def_id);
            Instance {
                def: ty::InstanceDef::Virtual(def_id, index),
                substs: rcvr_substs
            }
        }
        traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => {
            Instance {
                def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
                substs: rcvr_substs
            }
        }
        _ => {
            bug!("static call to invalid vtable: {:?}", vtbl)
        }
    }
}

/// The point where linking happens. Resolve a (def_id, substs)
/// pair to an instance.
pub fn resolve<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    substs: &'tcx Substs<'tcx>
) -> Instance<'tcx> {
    debug!("resolve(def_id={:?}, substs={:?})",
           def_id, substs);
    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
        debug!(" => associated item, attempting to find impl");
        let item = tcx.associated_item(def_id);
        resolve_associated_item(tcx, &item, trait_def_id, substs)
    } else {
        let item_type = def_ty(tcx, def_id, substs);
        let def = match item_type.sty {
            ty::TyFnDef(..) if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic ||
                    f.abi() == Abi::PlatformIntrinsic
                } =>
            {
                debug!(" => intrinsic");
                ty::InstanceDef::Intrinsic(def_id)
            }
            _ => {
                if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                    let ty = substs.type_at(0);
                    if type_needs_drop(tcx, ty) {
                        debug!(" => nontrivial drop glue");
                        ty::InstanceDef::DropGlue(def_id, Some(ty))
                    } else {
                        debug!(" => trivial drop glue");
                        ty::InstanceDef::DropGlue(def_id, None)
                    }
                } else {
                    debug!(" => free item");
                    ty::InstanceDef::Item(def_id)
                }
            }
        };
        Instance { def, substs }
    };
    debug!("resolve(def_id={:?}, substs={:?}) = {}",
           def_id, substs, result);
    result
}

pub fn resolve_drop_in_place<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    ty: Ty<'tcx>)
    -> ty::Instance<'tcx>
{
    let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
    let substs = tcx.intern_substs(&[Kind::from(ty)]);
    resolve(tcx, def_id, substs)
}

pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           source_ty: Ty<'tcx>,
                                           target_ty: Ty<'tcx>)
                                           -> CustomCoerceUnsized {
    let trait_ref = ty::Binder(ty::TraitRef {
        def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
        substs: tcx.mk_substs_trait(source_ty, &[target_ty])
    });

    match tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), trait_ref) {
        traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
            tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
        }
        vtable => {
            bug!("invalid CoerceUnsized vtable: {:?}", vtable);
        }
    }
}

/// Returns the normalized type of a struct field
pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          param_substs: &Substs<'tcx>,
                          f: &'tcx ty::FieldDef)
                          -> Ty<'tcx>
{
    tcx.normalize_associated_type(&f.ty(tcx, param_substs))
}

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

use abi::Abi;
use common::*;

use rustc::hir::def_id::DefId;
use rustc::middle::lang_items::DropInPlaceFnLangItem;
use rustc::traits;
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};

use syntax::codemap::DUMMY_SP;

pub use rustc::ty::Instance;

fn fn_once_adapter_instance<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    closure_did: DefId,
    substs: ty::ClosureSubsts<'tcx>,
    ) -> Instance<'tcx> {
    debug!("fn_once_adapter_shim({:?}, {:?})",
           closure_did,
           substs);
    let fn_once = tcx.lang_items().fn_once_trait().unwrap();
    let call_once = tcx.associated_items(fn_once)
        .find(|it| it.kind == ty::AssociatedKind::Method)
        .unwrap().def_id;
    let def = ty::InstanceDef::ClosureOnceShim { call_once };

    let self_ty = tcx.mk_closure_from_closure_substs(
        closure_did, substs);

    let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs);
    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
    assert_eq!(sig.inputs().len(), 1);
    let substs = tcx.mk_substs([
        Kind::from(self_ty),
        Kind::from(sig.inputs()[0]),
    ].iter().cloned());

    debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
    Instance { def, substs }
}

fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
                              trait_closure_kind: ty::ClosureKind)
                              -> Result<bool, ()>
{
    match (actual_closure_kind, trait_closure_kind) {
        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
            // No adapter needed.
           Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
            // `fn(&mut self, ...)`. In fact, at trans time, these are
            // basically the same thing, so we can just return llfn.
            Ok(false)
        }
        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
            // self, ...)`.  We want a `fn(self, ...)`. We can produce
            // this by doing something like:
            //
            //     fn call_once(self, ...) { call_mut(&self, ...) }
            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
            //
            // These are both the same at trans time.
            Ok(true)
        }
        _ => Err(()),
    }
}

pub fn resolve_closure<'a, 'tcx> (
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    substs: ty::ClosureSubsts<'tcx>,
    requested_kind: ty::ClosureKind)
    -> Instance<'tcx>
{
    let actual_kind = tcx.closure_kind(def_id);

    match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
        Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
        _ => Instance::new(def_id, substs.substs)
    }
}

fn resolve_associated_item<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    trait_item: &ty::AssociatedItem,
    trait_id: DefId,
    rcvr_substs: &'tcx Substs<'tcx>
) -> Instance<'tcx> {
    let def_id = trait_item.def_id;
    debug!("resolve_associated_item(trait_item={:?}, \
                                    trait_id={:?}, \
                                    rcvr_substs={:?})",
           def_id, trait_id, rcvr_substs);

    let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
    let vtbl = tcx.trans_fulfill_obligation(
        DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref));

    // Now that we know which impl is being used, we can dispatch to
    // the actual function:
    match vtbl {
        traits::VtableImpl(impl_data) => {
            let (def_id, substs) = traits::find_associated_item(
                tcx, trait_item, rcvr_substs, &impl_data);
            let substs = tcx.erase_regions(&substs);
            ty::Instance::new(def_id, substs)
        }
        traits::VtableGenerator(closure_data) => {
            Instance {
                def: ty::InstanceDef::Item(closure_data.closure_def_id),
                substs: closure_data.substs.substs
            }
        }
        traits::VtableClosure(closure_data) => {
            let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
            resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                            trait_closure_kind)
        }
        traits::VtableFnPointer(ref data) => {
            Instance {
                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
                substs: rcvr_substs
            }
        }
        traits::VtableObject(ref data) => {
            let index = tcx.get_vtable_index_of_object_method(data, def_id);
            Instance {
                def: ty::InstanceDef::Virtual(def_id, index),
                substs: rcvr_substs
            }
        }
        traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => {
            Instance {
                def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()),
                substs: rcvr_substs
            }
        }
        _ => {
            bug!("static call to invalid vtable: {:?}", vtbl)
        }
    }
}

/// The point where linking happens. Resolve a (def_id, substs)
/// pair to an instance.
pub fn resolve<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    substs: &'tcx Substs<'tcx>
) -> Instance<'tcx> {
    debug!("resolve(def_id={:?}, substs={:?})",
           def_id, substs);
    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
        debug!(" => associated item, attempting to find impl");
        let item = tcx.associated_item(def_id);
        resolve_associated_item(tcx, &item, trait_def_id, substs)
    } else {
        let item_type = def_ty(tcx, def_id, substs);
        let def = match item_type.sty {
            ty::TyFnDef(..) if {
                    let f = item_type.fn_sig(tcx);
                    f.abi() == Abi::RustIntrinsic ||
                    f.abi() == Abi::PlatformIntrinsic
                } =>
            {
                debug!(" => intrinsic");
                ty::InstanceDef::Intrinsic(def_id)
            }
            _ => {
                if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                    let ty = substs.type_at(0);
                    if type_needs_drop(tcx, ty) {
                        debug!(" => nontrivial drop glue");
                        ty::InstanceDef::DropGlue(def_id, Some(ty))
                    } else {
                        debug!(" => trivial drop glue");
                        ty::InstanceDef::DropGlue(def_id, None)
                    }
                } else {
                    debug!(" => free item");
                    ty::InstanceDef::Item(def_id)
                }
            }
        };
        Instance { def, substs }
    };
    debug!("resolve(def_id={:?}, substs={:?}) = {}",
           def_id, substs, result);
    result
}

pub fn resolve_drop_in_place<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    ty: Ty<'tcx>)
    -> ty::Instance<'tcx>
{
    let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
    let substs = tcx.intern_substs(&[Kind::from(ty)]);
    resolve(tcx, def_id, substs)
}

pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           source_ty: Ty<'tcx>,
                                           target_ty: Ty<'tcx>)
                                           -> CustomCoerceUnsized {
    let trait_ref = ty::Binder(ty::TraitRef {
        def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
        substs: tcx.mk_substs_trait(source_ty, &[target_ty])
    });

    match tcx.trans_fulfill_obligation(
        DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), trait_ref) {
        traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
            tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
        }
        vtable => {
            bug!("invalid CoerceUnsized vtable: {:?}", vtable);
        }
    }
}

/// Returns the normalized type of a struct field
pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          param_substs: &Substs<'tcx>,
                          f: &'tcx ty::FieldDef)
                          -> Ty<'tcx>
{
    tcx.normalize_associated_type(&f.ty(tcx, param_substs))
}

<|endoftext|>


<commit_before>use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::main_body_opts;
use core::ops::Range;
use pulldown_cmark::{Event, Parser, Tag};
use std::iter::Peekable;
use std::str::CharIndices;

crate const CHECK_INVALID_HTML_TAGS: Pass = Pass {
    name: "check-invalid-html-tags",
    run: check_invalid_html_tags,
    description: "detects invalid HTML tags in doc comments",
};

struct InvalidHtmlTagsLinter<'a, 'tcx> {
    cx: &'a mut DocContext<'tcx>,
}

crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
    if !cx.tcx.sess.is_nightly_build() {
        krate
    } else {
        let mut coll = InvalidHtmlTagsLinter { cx };

        coll.fold_crate(krate)
    }
}

const ALLOWED_UNCLOSED: &[&str] = &[
    "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
    "source", "track", "wbr",
];

fn drop_tag(
    tags: &mut Vec<(String, Range<usize>)>,
    tag_name: String,
    range: Range<usize>,
    f: &impl Fn(&str, &Range<usize>),
) {
    let tag_name_low = tag_name.to_lowercase();
    if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
        // If the tag is nested inside a "
` (the `h2` tag isn't required
        // but it helps for the visualization).
        f(&format!("unopened HTML tag `{}`", tag_name), &range);
    }
}

fn extract_html_tag(
    tags: &mut Vec<(String, Range<usize>)>,
    text: &str,
    range: &Range<usize>,
    start_pos: usize,
    iter: &mut Peekable<CharIndices<'_>>,
    f: &impl Fn(&str, &Range<usize>),
) {
    let mut tag_name = String::new();
    let mut is_closing = false;
    let mut prev_pos = start_pos;

    loop {
        let (pos, c) = match iter.peek() {
            Some((pos, c)) => (*pos, *c),
            // In case we reached the of the doc comment, we want to check that it's an
            // unclosed HTML tag. For example "///
 (prev_pos, '\0'),
        };
        prev_pos = pos;
        // Checking if this is a closing tag (like `</a>` for `<a>`).
        if c == '/' && tag_name.is_empty() {
            is_closing = true;
        } else if c.is_ascii_alphanumeric() {
            tag_name.push(c);
        } else {
            if !tag_name.is_empty() {
                let mut r = Range { start: range.start + start_pos, end: range.start + pos };
                if c == '>' {
                    // In case we have a tag without attribute, we can consider the span to
                    // refer to it fully.
                    r.end += 1;
                }
                if is_closing {
                    // In case we have "
" or even "
".
                    if c != '>' {
                        if !c.is_whitespace() {
                            // It seems like it's not a valid HTML tag.
                            break;
                        }
                        let mut found = false;
                        for (new_pos, c) in text[pos..].char_indices() {
                            if !c.is_whitespace() {
                                if c == '>' {
                                    r.end = range.start + new_pos + 1;
                                    found = true;
                                }
                                break;
                            }
                        }
                        if !found {
                            break;
                        }
                    }
                    drop_tag(tags, tag_name, r, f);
                } else {
                    tags.push((tag_name, r));
                }
            }
            break;
        }
        iter.next();
    }
}

fn extract_tags(
    tags: &mut Vec<(String, Range<usize>)>,
    text: &str,
    range: Range<usize>,
    is_in_comment: &mut Option<Range<usize>>,
    f: &impl Fn(&str, &Range<usize>),
) {
    let mut iter = text.char_indices().peekable();

    while let Some((start_pos, c)) = iter.next() {
        if is_in_comment.is_some() {
            if text[start_pos..].starts_with("-->") {
                *is_in_comment = None;
            }
        } else if c == '<' {
            if text[start_pos..].starts_with("") {
                *is_in_comment = None;
            }
        } else if c == '<' {
            if text[start_pos..].starts_with("


<commit_before>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));
                        });
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        desync.async(move |_core| {
                            // Mark the target stream as closed
                            let notify = {
                                let mut stream_core = stream_core.lock().unwrap();
                                stream_core.closed = true;
                                stream_core.notify.take()
                            };
                            notify.map(|notify| notify.notify());
                        });

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let notify = {
                        let mut stream_core = stream_core.lock().unwrap();

                        stream_core.pending.push_back(next_item);
                        stream_core.notify.take()
                    };
                    notify.map(|notify| notify.notify());
                });

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<commit_msg>Don't immediately poll for a new value from the stream until the old one has finished processing<commit_after>//!
//! Desync pipes provide a way to generate and process streams via a `Desync` object
//!
//! Pipes are an excellent way to interface `Desync` objects and the futures library. Piping
//! a stream into a `Desync` object is equivalent to spawning it with an executor, except
//! without the need to dedicate a thread to running it.
//!
//! There are two kinds of pipe. The `pipe_in` function creates a pipe that processes each
//! value made available from a stream on a desync object as they arrive, producing no
//! results. This is useful for cases where a `Desync` object is being used as the endpoint
//! for some data processing (for example, to insert the results of an operation into an
//! asynchronous database object).
//!
//! The `pipe` function pipes data through an object. For every input value, it produces
//! an output value. This is good for creating streams that perform some kind of asynchronous
//! processing operation or that need to access data from inside a `Desync` object.
//!
//! Here's an example of using `pipe_in` to store data in a `HashSet`:
//!
//! ```
//! # extern crate futures;
//! # extern crate desync;
//! # use std::collections::HashSet;
//! # use std::sync::*;
//! #
//! use futures::sync::mpsc;
//! use futures::executor;
//! use desync::*;
//!
//! let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
//! let (sender, receiver)  = mpsc::channel(5);
//!
//! pipe_in(Arc::clone(&desync_hashset), receiver, |hashset, value| { value.map(|value| hashset.insert(value)); });
//!
//! let mut sender = executor::spawn(sender);
//! sender.wait_send("Test".to_string());
//! sender.wait_send("Another value".to_string());
//! #
//! # assert!(desync_hashset.sync(|hashset| hashset.contains(&("Test".to_string()))))
//! ```
//!

use super::desync::*;

use futures::*;
use futures::executor;
use futures::executor::Spawn;

use std::sync::*;
use std::result::Result;
use std::collections::VecDeque;

lazy_static! {
    /// The shared queue where we monitor for updates to the active pipe streams
    static ref PIPE_MONITOR: PipeMonitor = PipeMonitor::new();
}

/// The maximum number of items to queue on a pipe stream before we stop accepting new input
const PIPE_BACKPRESSURE_COUNT: usize = 5;

///
/// Pipes a stream into a desync object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received.
///
/// This takes a weak reference to the passed in `Desync` object, so the pipe will stop if it's
/// the only thing referencing this object.
///
/// Piping a stream to a `Desync` like this will cause it to start executing: ie, this is
/// similar to calling `executor::spawn(stream)`, except that the stream will immediately
/// start draining into the `Desync` object.
///
pub fn pipe_in<Core, S, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn)
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> () {

    // Need a mutable version of the stream
    let mut stream = stream;

    // We stop processing once the desync object is no longer used anywhere else
    let desync = Arc::downgrade(&desync);

    // Wrap the process fn up so we can call it asynchronously
    // (it doesn't really need to be in a mutex as it's only called by our object but we need to make it pass Rust's checks and we don't have a way to specify this at the moment)
    let process = Arc::new(Mutex::new(process));

    // Monitor the stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let desync      = desync.upgrade();

            if let Some(desync) = desync {
                // Read the current status of the stream
                let process     = Arc::clone(&process);
                let next        = stream.poll();

                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the stream is finished
                    Ok(Async::Ready(None)) => { return Ok(Async::Ready(())); }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => {
                        let when_ready = task::current();

                        // Process the value on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Ok(next));

                            when_ready.notify();
                        });

                        // Wake again when the processing finishes
                        return Ok(Async::NotReady);
                    },

                    // Stream returned an error
                    Err(e) => {
                        // Process the error on the stream
                        desync.async(move |core| {
                            let mut process = process.lock().unwrap();
                            let process     = &mut *process;
                            process(core, Err(e));
                        });
                    },
                }
            } else {
                // The desync target is no longer available - indicate that we've completed monitoring
                return Ok(Async::Ready(()));
            }
        }
    });
}

///
/// Pipes a stream into this object. Whenever an item becomes available on the stream, the
/// processing function is called asynchronously with the item that was received. The
/// return value is placed onto the output stream.
///
/// Unlike `pipe_in`, this keeps a strong reference to the `Desync` object so the processing
/// will continue so long as the input stream has data and the output stream is not dropped.
///
/// The input stream will start executing and reading values immediately when this is called.
/// Dropping the output stream will cause the pipe to be closed (the input stream will be
/// dropped and no further processing will occur).
///
/// This example demonstrates how to create a simple demonstration pipe that takes hashset values
/// and returns a stream indicating whether or not they were already included:
///
/// ```
/// # extern crate futures;
/// # extern crate desync;
/// # use std::collections::HashSet;
/// # use std::sync::*;
/// #
/// use futures::sync::mpsc;
/// use futures::executor;
/// use desync::*;
///
/// let desync_hashset      = Arc::new(Desync::new(HashSet::new()));
/// let (sender, receiver)  = mpsc::channel::<String>(5);
///
/// let value_inserted = pipe(Arc::clone(&desync_hashset), receiver,
///     |hashset, value| { value.map(|value| (value.clone(), hashset.insert(value))) });
///
/// let mut sender = executor::spawn(sender);
/// sender.wait_send("Test".to_string());
/// sender.wait_send("Another value".to_string());
/// sender.wait_send("Test".to_string());
///
/// let mut value_inserted = executor::spawn(value_inserted);
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Another value".to_string(), true))));
/// assert!(value_inserted.wait_stream() == Some(Ok(("Test".to_string(), false))));
/// ```
///
pub fn pipe<Core, S, Output, OutputErr, ProcessFn>(desync: Arc<Desync<Core>>, stream: S, process: ProcessFn) -> PipeStream<Output, OutputErr>
where   Core:       'static+Send,
        S:          'static+Send+Stream,
        S::Item:    Send,
        S::Error:   Send,
        Output:     'static+Send,
        OutputErr:  'static+Send,
        ProcessFn:  'static+Send+FnMut(&mut Core, Result<S::Item, S::Error>) -> Result<Output, OutputErr> {

    // Fetch the input stream and prepare the process function for async calling
    let mut input_stream    = stream;
    let process             = Arc::new(Mutex::new(process));

    // Create the output stream
    let output_stream   = PipeStream::new();
    let stream_core     = Arc::clone(&output_stream.core);
    let stream_core     = Arc::downgrade(&stream_core);

    // Monitor the input stream and pass data to the output stream
    PIPE_MONITOR.monitor(move || {
        loop {
            let stream_core = stream_core.upgrade();

            if let Some(stream_core) = stream_core {
                // Defer processing if the stream core is full
                {
                    // Fetch the core
                    let mut stream_core = stream_core.lock().unwrap();

                    // If the pending queue is full, then stop processing events
                    if stream_core.pending.len() >= stream_core.max_pipe_depth {
                        // Wake when the stream accepts some input
                        stream_core.backpressure_release_notify = Some(task::current());

                        // Go back to sleep without reading from the stream
                        return Ok(Async::NotReady);
                    }
                }

                // Read the current status of the stream
                let process         = Arc::clone(&process);
                let next            = input_stream.poll();
                let mut next_item;

                // Work out what the next item to pass to the process function should be
                match next {
                    // Just wait if the stream is not ready
                    Ok(Async::NotReady) => { return Ok(Async::NotReady); },

                    // Stop processing when the input stream is finished
                    Ok(Async::Ready(None)) => {
                        desync.async(move |_core| {
                            // Mark the target stream as closed
                            let notify = {
                                let mut stream_core = stream_core.lock().unwrap();
                                stream_core.closed = true;
                                stream_core.notify.take()
                            };
                            notify.map(|notify| notify.notify());
                        });

                        // Pipe has finished
                        return Ok(Async::Ready(()));
                    }

                    // Stream returned a value
                    Ok(Async::Ready(Some(next))) => next_item = Ok(next),

                    // Stream returned an error
                    Err(e) => next_item = Err(e),
                }

                // Send the next item to be processed
                let when_finished = task::current();
                desync.async(move |core| {
                    // Process the next item
                    let mut process     = process.lock().unwrap();
                    let process         = &mut *process;
                    let next_item       = process(core, next_item);

                    // Send to the pipe stream
                    let notify = {
                        let mut stream_core = stream_core.lock().unwrap();

                        stream_core.pending.push_back(next_item);
                        stream_core.notify.take()
                    };
                    notify.map(|notify| notify.notify());

                    when_finished.notify();
                });

                // Poll again when the task is complete
                return Ok(Async::NotReady);

            } else {
                // We stop processing once nothing is reading from the target stream
                return Ok(Async::Ready(()));
            }
        }
    });

    // The pipe stream is the result
    output_stream
}

///
/// The shared data for a pipe stream
///
struct PipeStreamCore<Item, Error>  {
    /// The maximum number of items we allow to be queued in this stream before producing backpressure
    max_pipe_depth: usize,

    /// The pending data for this stream
    pending: VecDeque<Result<Item, Error>>,

    /// True if the input stream has closed (the stream is closed once this is true and there are no more pending items)
    closed: bool,

    /// The task to notify when the stream changes
    notify: Option<task::Task>,

    /// The task to notify when we reduce the amount of pending data
    backpressure_release_notify: Option<task::Task>
}

///
/// A stream generated by a pipe
///
pub struct PipeStream<Item, Error> {
    core: Arc<Mutex<PipeStreamCore<Item, Error>>>
}

impl<Item, Error> PipeStream<Item, Error> {
    ///
    /// Creates a new, empty, pipestream
    ///
    fn new() -> PipeStream<Item, Error> {
        PipeStream {
            core: Arc::new(Mutex::new(PipeStreamCore {
                max_pipe_depth:                 PIPE_BACKPRESSURE_COUNT,
                pending:                        VecDeque::new(),
                closed:                         false,
                notify:                         None,
                backpressure_release_notify:    None
            }))
        }
    }

    ///
    /// Sets the number of items that this pipe stream will buffer before producing backpressure
    ///
    /// If this call is not made, this will be set to 5.
    ///
    pub fn set_backpressure_depth(&mut self, max_depth: usize) {
        self.core.lock().unwrap().max_pipe_depth = max_depth;
    }
}

impl<Item, Error> Drop for PipeStream<Item, Error> {
    fn drop(&mut self) {
        let mut core = self.core.lock().unwrap();

        // Flush the pending queue
        core.pending = VecDeque::new();

        // TODO: wake the monitor and stop listening to the source stream
        // (Right now this will happen next time the source stream produces data)
    }
}

impl<Item, Error> Stream for PipeStream<Item, Error> {
    type Item   = Item;
    type Error  = Error;

    fn poll(&mut self) -> Poll<Option<Item>, Error> {
        // Fetch the core
        let mut core = self.core.lock().unwrap();

        if let Some(item) = core.pending.pop_front() {
            // Value waiting at the start of the stream
            core.backpressure_release_notify.take().map(|notify| notify.notify());

            match item {
                Ok(item)    => Ok(Async::Ready(Some(item))),
                Err(erm)    => Err(erm)
            }
        } else if core.closed {
            // No more data will be returned from this stream
            Ok(Async::Ready(None))
        } else {
            // Stream not ready
            core.notify = Some(task::current());

            Ok(Async::NotReady)
        }
    }
}

///
/// The main polling component for that implements the stream pipes
///
struct PipeMonitor {
}

///
/// Provides the 'Notify' interface for a polling function with a particular ID
///
struct PipeNotify<PollFn: Send> {
    next_poll: Arc<Desync<Option<Spawn<PollFn>>>>
}

impl PipeMonitor {
    ///
    /// Creates a new poll thread
    ///
    pub fn new() -> PipeMonitor {
        PipeMonitor {
        }
    }

    ///
    /// Performs a polling operation on a poll
    ///
    fn poll<PollFn>(this_poll: &mut Option<Spawn<PollFn>>, next_poll: Arc<Desync<Option<Spawn<PollFn>>>>)
    where PollFn: 'static+Send+Future<Item=(), Error=()> {
        // If the polling function exists...
        if let Some(mut poll) = this_poll.take() {
            // Create a notification
            let notify = PipeNotify {
                next_poll: next_poll
            };
            let notify = Arc::new(notify);

            // Poll the function
            let poll_result = poll.poll_future_notify(&notify, 0);

            // Keep the polling function alive if it has not finished yet
            if poll_result != Ok(Async::Ready(())) {
                // The take() call means that the polling won't continue unless we pass it forward like this
                *this_poll = Some(poll);
            }
        }
    }

    ///
    /// Adds a polling function to the current thread. It will be called using the futures
    /// notification system (ie, can call things like the stream poll function)
    ///
    pub fn monitor<PollFn>(&self, poll_fn: PollFn)
    where PollFn: 'static+Send+FnMut() -> Poll<(), ()> {
        // Turn the polling function into a future (it will complete when monitoring is complete)
        let poll_fn     = future::poll_fn(poll_fn);

        // Spawn it with an executor
        let poll_fn     = executor::spawn(poll_fn);

        // Create a desync object for polling
        let poll_fn     = Arc::new(Desync::new(Some(poll_fn)));
        let next_poll   = Arc::clone(&poll_fn);

        // Perform the initial polling
        poll_fn.sync(move |poll_fn| Self::poll(poll_fn, next_poll));
    }
}

impl<PollFn> executor::Notify for PipeNotify<PollFn>
where PollFn: 'static+Send+Future<Item=(), Error=()> {
    fn notify(&self, _id: usize) {
        // Poll the future whenever we're notified
        let next_poll = Arc::clone(&self.next_poll);
        self.next_poll.sync(move |poll_fn| PipeMonitor::poll(poll_fn, next_poll));
    }
}
<|endoftext|>


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

use std::rand::{Rand, Rng, SeedableRng, XorShiftRng};
use std::num::SignedInt;

use math;

const TABLE_SIZE: usize = 256;

#[allow(missing_copy_implementations)]
pub struct Seed {
    x_values: [u8; TABLE_SIZE],
    y_values: [u8; TABLE_SIZE],
    z_values: [u8; TABLE_SIZE],
    w_values: [u8; TABLE_SIZE],
}

impl Rand for Seed {
    fn rand<R: Rng>(rng: &mut R) -> Seed {
        let mut x_values: Vec<u8> = ::std::iter::range_inclusive(0, (TABLE_SIZE - 1) as u8).collect();
        let mut y_values: Vec<u8> = x_values.clone();
        let mut z_values: Vec<u8> = x_values.clone();
        let mut w_values: Vec<u8> = x_values.clone();

        rng.shuffle(&mut *x_values);
        rng.shuffle(&mut *y_values);
        rng.shuffle(&mut *z_values);
        rng.shuffle(&mut *w_values);

        // It's unfortunate that this double-initializes the array, but Rust doesn't currently provide a
        // clean way to do this in one pass. Hopefully won't matter, as Seed creation will usually be a
        // one-time event.
        let mut seed = Seed {
            x_values: [0; TABLE_SIZE],
            y_values: [0; TABLE_SIZE],
            z_values: [0; TABLE_SIZE],
            w_values: [0; TABLE_SIZE],
        };

        let x_iter = x_values.iter().cycle();
        for (x, y) in seed.x_values.iter_mut().zip(x_iter) { *x = *y }
        let y_iter = y_values.iter().cycle();
        for (x, y) in seed.y_values.iter_mut().zip(y_iter) { *x = *y }
        let z_iter = z_values.iter().cycle();
        for (x, y) in seed.z_values.iter_mut().zip(z_iter) { *x = *y }
        let w_iter = w_values.iter().cycle();
        for (x, y) in seed.w_values.iter_mut().zip(w_iter) { *x = *y }
        seed
    }
}

impl Seed {
    pub fn new(seed: u32) -> Seed {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: SignedInt>(&self, x: T) -> usize {
        self.x_values[math::cast::<T, usize>(x & math::cast(TABLE_SIZE - 1))] as usize
    }

    #[inline(always)]
    pub fn get2<T: SignedInt>(&self, pos: math::Point2<T>) -> usize {
        self.get1(pos[0]) ^ self.y_values[math::cast::<T, usize>(pos[1] & math::cast(TABLE_SIZE - 1))] as usize
    }

    #[inline(always)]
    pub fn get3<T: SignedInt>(&self, pos: math::Point3<T>) -> usize {
        self.get2([pos[0], pos[1]]) ^ self.z_values[math::cast::<T, usize>(pos[2] & math::cast(TABLE_SIZE - 1))] as usize
    }

    #[inline(always)]
    pub fn get4<T: SignedInt>(&self, pos: math::Point4<T>) -> usize {
        self.get3([pos[0], pos[1], pos[2]]) ^ self.w_values[math::cast::<T, usize>(pos[3] & math::cast(TABLE_SIZE - 1))] as usize
    }
}

#[cfg(test)]
mod tests {
    use std::rand::random;
    use perlin::perlin3;
    use super::Seed;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&Seed::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<commit_msg>Change Seed back to one permutation table<commit_after>// Copyright 2015 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::rand::{Rand, Rng, SeedableRng, XorShiftRng};
use std::num::SignedInt;

use math;

const TABLE_SIZE: usize = 256;

#[allow(missing_copy_implementations)]
pub struct Seed {
    values: [u8; TABLE_SIZE],
}

impl Rand for Seed {
    fn rand<R: Rng>(rng: &mut R) -> Seed {
        let mut seq: Vec<u8> = ::std::iter::range_inclusive(0, (TABLE_SIZE - 1) as u8).collect();
        rng.shuffle(&mut *seq);

        // It's unfortunate that this double-initializes the array, but Rust doesn't currently provide a
        // clean way to do this in one pass. Hopefully won't matter, as Seed creation will usually be a
        // one-time event.
        let mut seed = Seed { values: [0; TABLE_SIZE] };
        let seq_it = seq.iter();
        for (x, y) in seed.values.iter_mut().zip(seq_it) { *x = *y }
        seed
    }
}

impl Seed {
    pub fn new(seed: u32) -> Seed {
        let mut rng: XorShiftRng = SeedableRng::from_seed([1, seed, seed, seed]);
        rng.gen()
    }

    #[inline(always)]
    pub fn get1<T: SignedInt>(&self, x: T) -> usize {
        let x: usize = math::cast(x & math::cast(0xff));
        self.values[x] as usize
    }

    #[inline(always)]
    pub fn get2<T: SignedInt>(&self, pos: math::Point2<T>) -> usize {
        let y: usize = math::cast(pos[1] & math::cast(0xff));
        self.values[self.get1(pos[0]) ^ y] as usize
    }

    #[inline(always)]
    pub fn get3<T: SignedInt>(&self, pos: math::Point3<T>) -> usize {
        let z: usize = math::cast(pos[2] & math::cast(0xff));
        self.values[self.get2([pos[0], pos[1]]) ^ z] as usize
    }

    #[inline(always)]
    pub fn get4<T: SignedInt>(&self, pos: math::Point4<T>) -> usize {
        let w: usize = math::cast(pos[3] & math::cast(0xff));
        self.values[self.get3([pos[0], pos[1], pos[2]]) ^ w] as usize
    }
}

#[cfg(test)]
mod tests {
    use std::rand::random;
    use perlin::perlin3;
    use super::Seed;

    #[test]
    fn test_random_seed() {
        let _ = perlin3::<f32>(&random(), &[1.0, 2.0, 3.0]);
    }

    #[test]
    fn test_negative_params() {
        let _ = perlin3::<f32>(&Seed::new(0), &[-1.0, 2.0, 3.0]);
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use std::{fs, io};
use std::fs::File;
use std::path::PathBuf;

use datatype::{Config, DeviceReport, DownloadComplete, Error, Package,
               UpdateReport, UpdateRequest, UpdateRequestId, Url};
use http::{Client, Response};

/// Encapsulate the client configuration and HTTP client used for
/// software-over-the-air updates.
pub struct Sota<'c, 'h> {
    config: &'c Config,
    client: &'h Client,
}

impl<'c, 'h> Sota<'c, 'h> {
    /// Creates a new instance for Sota communication.
    pub fn new(config: &'c Config, client: &'h Client) -> Sota<'c, 'h> {
        Sota { config: config, client: client }
    }

    /// Takes a path and returns a new endpoint of the format
    /// `<Core server>/api/v1/device_updates/<device-id>$path`.
    fn endpoint(&self, path: &str) -> Url {
        let endpoint = format!("/api/v1/device_updates/{}{}", self.config.device.uuid, path);
        self.config.core.server.join(&endpoint).expect("couldn't build endpoint url")
    }

    /// Returns the path to a package on the device.
    fn package_path(&self, id: UpdateRequestId) -> Result<String, Error> {
        let mut path = PathBuf::new();
        path.push(&self.config.device.packages_dir);
        path.push(id);
        Ok(try!(path.to_str().ok_or(Error::Parse(format!("Path is not valid UTF-8: {:?}", path)))).to_string())
    }

    /// Query the Core server for any pending or in-flight package updates.
    pub fn get_update_requests(&mut self) -> Result<Vec<UpdateRequest>, Error> {
        let resp_rx = self.client.get(self.endpoint("/queued"), None);
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't get new updates".to_string())));
        let data    = match resp {
            Response::Success(data) => data,
            Response::Failed(data)  => return Err(Error::from(data)),
            Response::Error(err)    => return Err(err)
        };

        let text = try!(String::from_utf8(data.body));
        Ok(try!(json::decode::<Vec<UpdateRequest>>(&text)))
    }

    /// Download a specific update from the Core server.
    pub fn download_update(&mut self, id: UpdateRequestId) -> Result<DownloadComplete, Error> {
        let resp_rx = self.client.get(self.endpoint(&format!("/{}/download", id)), None);
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't download update".to_string())));
        let data    = match resp {
            Response::Success(data) => data,
            Response::Failed(data)  => return Err(Error::from(data)),
            Response::Error(err)    => return Err(err)
        };

        let path     = try!(self.package_path(id.clone()));
        let mut file = try!(File::create(&path));
        let _        = io::copy(&mut &*data.body, &mut file);
        Ok(DownloadComplete {
            update_id:    id,
            update_image: path.to_string(),
            signature:    "".to_string()
        })
    }

    /// Install an update using the package manager.
    pub fn install_update(&mut self, id: UpdateRequestId) -> Result<UpdateReport, UpdateReport> {
        let ref pacman = self.config.device.package_manager;
        let path       = self.package_path(id.clone()).expect("install_update expects a valid path");
        pacman.install_package(&path).and_then(|(code, output)| {
            let _ = fs::remove_file(&path).unwrap_or_else(|err| error!("couldn't remove installed package: {}", err));
            Ok(UpdateReport::single(id.clone(), code, output))
        }).or_else(|(code, output)| {
            Err(UpdateReport::single(id.clone(), code, output))
        })
    }

    /// Send a list of the currently installed packages to the Core server.
    pub fn send_installed_packages(&mut self, packages: &Vec<Package>) -> Result<(), Error> {
        let body    = try!(json::encode(packages));
        let resp_rx = self.client.put(self.endpoint("/installed"), Some(body.into_bytes()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send installed packages".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Send the outcome of a package update to the Core server.
    pub fn send_update_report(&mut self, update_report: &UpdateReport) -> Result<(), Error> {
        let report  = DeviceReport::new(&self.config.device.uuid, update_report);
        let body    = try!(json::encode(&report));
        let url     = self.endpoint(&format!("/{}", report.device));
        let resp_rx = self.client.post(url, Some(body.into_bytes()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send update report".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Send system information from the device to the Core server.
    pub fn send_system_info(&mut self, body: &str) -> Result<(), Error> {
        let resp_rx = self.client.put(self.endpoint("/system_info"), Some(body.as_bytes().to_vec()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send system info".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Package, UpdateRequest, UpdateRequestStatus};
    use http::TestClient;

    #[test]
    fn test_get_update_requests() {
        let pending_update = UpdateRequest {
            requestId: "someid".to_string(),
            status: UpdateRequestStatus::Pending,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            installPos: 0,
            createdAt: "2010-01-01".to_string()
        };

        let json = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut sota = Sota {
            config: &Config::default(),
            client: &mut TestClient::from(vec![json.to_string()]),
        };

        let updates: Vec<UpdateRequest> = sota.get_update_requests().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }
}
<commit_msg>Use new 'mydevice' endpoint on sota-core<commit_after>use rustc_serialize::json;
use std::{fs, io};
use std::fs::File;
use std::path::PathBuf;

use datatype::{Config, DownloadComplete, Error, Package,
               UpdateReport, UpdateRequest, UpdateRequestId, Url};
use http::{Client, Response};

/// Encapsulate the client configuration and HTTP client used for
/// software-over-the-air updates.
pub struct Sota<'c, 'h> {
    config: &'c Config,
    client: &'h Client,
}

impl<'c, 'h> Sota<'c, 'h> {
    /// Creates a new instance for Sota communication.
    pub fn new(config: &'c Config, client: &'h Client) -> Sota<'c, 'h> {
        Sota { config: config, client: client }
    }

    /// Takes a path and returns a new endpoint of the format
    /// `<Core server>/api/v1/mydevice/<device-id>$path`.
    fn endpoint(&self, path: &str) -> Url {
        let endpoint = format!("/api/v1/mydevice/{}{}", self.config.device.uuid, path);
        self.config.core.server.join(&endpoint).expect("couldn't build endpoint url")
    }

    /// Returns the path to a package on the device.
    fn package_path(&self, id: UpdateRequestId) -> Result<String, Error> {
        let mut path = PathBuf::new();
        path.push(&self.config.device.packages_dir);
        path.push(id);
        Ok(try!(path.to_str().ok_or(Error::Parse(format!("Path is not valid UTF-8: {:?}", path)))).to_string())
    }

    /// Query the Core server for any pending or in-flight package updates.
    pub fn get_update_requests(&mut self) -> Result<Vec<UpdateRequest>, Error> {
        let resp_rx = self.client.get(self.endpoint("/updates"), None);
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't get new updates".to_string())));
        let data    = match resp {
            Response::Success(data) => data,
            Response::Failed(data)  => return Err(Error::from(data)),
            Response::Error(err)    => return Err(err)
        };

        let text = try!(String::from_utf8(data.body));
        Ok(try!(json::decode::<Vec<UpdateRequest>>(&text)))
    }

    /// Download a specific update from the Core server.
    pub fn download_update(&mut self, id: UpdateRequestId) -> Result<DownloadComplete, Error> {
        let resp_rx = self.client.get(self.endpoint(&format!("/updates/{}/download", id)), None);
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't download update".to_string())));
        let data    = match resp {
            Response::Success(data) => data,
            Response::Failed(data)  => return Err(Error::from(data)),
            Response::Error(err)    => return Err(err)
        };

        let path     = try!(self.package_path(id.clone()));
        let mut file = try!(File::create(&path));
        let _        = io::copy(&mut &*data.body, &mut file);
        Ok(DownloadComplete {
            update_id:    id,
            update_image: path.to_string(),
            signature:    "".to_string()
        })
    }

    /// Install an update using the package manager.
    pub fn install_update(&mut self, id: UpdateRequestId) -> Result<UpdateReport, UpdateReport> {
        let ref pacman = self.config.device.package_manager;
        let path       = self.package_path(id.clone()).expect("install_update expects a valid path");
        pacman.install_package(&path).and_then(|(code, output)| {
            let _ = fs::remove_file(&path).unwrap_or_else(|err| error!("couldn't remove installed package: {}", err));
            Ok(UpdateReport::single(id.clone(), code, output))
        }).or_else(|(code, output)| {
            Err(UpdateReport::single(id.clone(), code, output))
        })
    }

    /// Send a list of the currently installed packages to the Core server.
    pub fn send_installed_packages(&mut self, packages: &Vec<Package>) -> Result<(), Error> {
        let body    = try!(json::encode(packages));
        let resp_rx = self.client.put(self.endpoint("/installed"), Some(body.into_bytes()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send installed packages".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Send the outcome of a package update to the Core server.
    pub fn send_update_report(&mut self, update_report: &UpdateReport) -> Result<(), Error> {
        let body    = try!(json::encode(&update_report.operation_results));
        let url     = self.endpoint(&format!("/updates/{}", update_report.update_id));
        let resp_rx = self.client.post(url, Some(body.into_bytes()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send update report".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }

    /// Send system information from the device to the Core server.
    pub fn send_system_info(&mut self, body: &str) -> Result<(), Error> {
        let resp_rx = self.client.put(self.endpoint("/system_info"), Some(body.as_bytes().to_vec()));
        let resp    = try!(resp_rx.recv().ok_or(Error::Client("couldn't send system info".to_string())));

        match resp {
            Response::Success(_)   => Ok(()),
            Response::Failed(data) => Err(Error::from(data)),
            Response::Error(err)   => Err(err)
        }
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json;

    use super::*;
    use datatype::{Config, Package, UpdateRequest, UpdateRequestStatus};
    use http::TestClient;

    #[test]
    fn test_get_update_requests() {
        let pending_update = UpdateRequest {
            requestId: "someid".to_string(),
            status: UpdateRequestStatus::Pending,
            packageId: Package {
                name: "fake-pkg".to_string(),
                version: "0.1.1".to_string()
            },
            installPos: 0,
            createdAt: "2010-01-01".to_string()
        };

        let json = format!("[{}]", json::encode(&pending_update).unwrap());
        let mut sota = Sota {
            config: &Config::default(),
            client: &mut TestClient::from(vec![json.to_string()]),
        };

        let updates: Vec<UpdateRequest> = sota.get_update_requests().unwrap();
        let ids: Vec<String> = updates.iter().map(|p| p.requestId.clone()).collect();
        assert_eq!(ids, vec!["someid".to_string()])
    }
}
<|endoftext|>