<commit_before>use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{is_trait_method, path_to_local_id, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;

use rustc_span::symbol::{sym, Ident};
use rustc_span::{MultiSpan, Span};

const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";

pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    check_needless_collect_direct_usage(expr, cx);
    check_needless_collect_indirect_usage(expr, cx);
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    if_chain! {
        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
        if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
        if let Some(generic_args) = chain_method.args;
        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
        let ty = cx.typeck_results().node_type(ty.hir_id);
        if is_type_diagnostic_item(cx, ty, sym::vec_type)
            || is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
            || match_type(cx, ty, &paths::BTREEMAP)
            || is_type_diagnostic_item(cx, ty, sym::hashmap_type);
        if let Some(sugg) = match &*method.ident.name.as_str() {
            "len" => Some("count()".to_string()),
            "is_empty" => Some("next().is_none()".to_string()),
            "contains" => {
                let contains_arg = snippet(cx, args[1].span, "??");
                let (arg, pred) = contains_arg
                    .strip_prefix('&')
                    .map_or(("&x", &*contains_arg), |s| ("x", s));
                Some(format!("any(|{}| x == {})", arg, pred))
            }
            _ => None,
        };
        then {
            span_lint_and_sugg(
                cx,
                NEEDLESS_COLLECT,
                method0_span.with_hi(expr.span.hi()),
                NEEDLESS_COLLECT_MSG,
                "replace with",
                sugg,
                Applicability::MachineApplicable,
            );
        }
    }
}

fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
        if let Some(ty) = ty {
            return Some(ty.hir_id);
        }

        if let Some(generic_args) = method_args {
            if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
                return Some(ty.hir_id);
            }
        }

        None
    }
    if let ExprKind::Block(block, _) = expr.kind {
        for stmt in block.stmts {
            if_chain! {
                if let StmtKind::Local(
                    Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
                    init: Some(init_expr), ty, .. }
                ) = stmt.kind;
                if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
                if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                if let Some(hir_id) = get_hir_id(*ty, method_name.args);
                if let ty = cx.typeck_results().node_type(hir_id);
                if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                    is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                    is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
                    match_type(cx, ty, &paths::LINKED_LIST);
                if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                if let [iter_call] = &*iter_calls;
                then {
                    let mut used_count_visitor = UsedCountVisitor {
                        cx,
                        id: *pat_id,
                        count: 0,
                    };
                    walk_block(&mut used_count_visitor, block);
                    if used_count_visitor.count > 1 {
                        return;
                    }

                    // Suggest replacing iter_call with iter_replacement, and removing stmt
                    let mut span = MultiSpan::from_span(collect_span);
                    span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
                    span_lint_and_then(
                        cx,
                        super::NEEDLESS_COLLECT,
                        span,
                        NEEDLESS_COLLECT_MSG,
                        |diag| {
                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
                            diag.multipart_suggestion(
                                iter_call.get_suggestion_text(),
                                vec![
                                    (stmt.span, String::new()),
                                    (iter_call.span, iter_replacement)
                                ],
                                Applicability::MachineApplicable,// MaybeIncorrect,
                            );
                        },
                    );
                }
            }
        }
    }
}

struct IterFunction {
    func: IterFunctionKind,
    span: Span,
}
impl IterFunction {
    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
        match &self.func {
            IterFunctionKind::IntoIter => String::new(),
            IterFunctionKind::Len => String::from(".count()"),
            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
            IterFunctionKind::Contains(span) => {
                let s = snippet(cx, *span, "..");
                if let Some(stripped) = s.strip_prefix('&') {
                    format!(".any(|x| x == {})", stripped)
                } else {
                    format!(".any(|x| x == *{})", s)
                }
            },
        }
    }
    fn get_suggestion_text(&self) -> &'static str {
        match &self.func {
            IterFunctionKind::IntoIter => {
                "use the original Iterator instead of collecting it and then producing a new one"
            },
            IterFunctionKind::Len => {
                "take the original Iterator's count instead of collecting it and finding the length"
            },
            IterFunctionKind::IsEmpty => {
                "check if the original Iterator has anything instead of collecting it and seeing if it's empty"
            },
            IterFunctionKind::Contains(_) => {
                "check if the original Iterator contains an element instead of collecting then checking"
            },
        }
    }
}
enum IterFunctionKind {
    IntoIter,
    Len,
    IsEmpty,
    Contains(Span),
}

struct IterFunctionVisitor {
    uses: Vec<IterFunction>,
    seen_other: bool,
    target: Ident,
}
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        // Check function calls on our collection
        if_chain! {
            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                let len = sym!(len);
                let is_empty = sym!(is_empty);
                let contains = sym!(contains);
                match method_name.ident.name {
                    sym::into_iter => self.uses.push(
                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
                    ),
                    name if name == len => self.uses.push(
                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
                    ),
                    name if name == is_empty => self.uses.push(
                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
                    ),
                    name if name == contains => self.uses.push(
                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
                    ),
                    _ => self.seen_other = true,
                }
                return
            }
        }
        // Check if the collection is used for anything else
        if_chain! {
            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                self.seen_other = true;
            } else {
                walk_expr(self, expr);
            }
        }
    }

    type Map = Map<'tcx>;
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

struct UsedCountVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    id: HirId,
    count: usize,
}

impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if path_to_local_id(expr, self.id) {
            self.count += 1;
        } else {
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
    }
}

/// Detect the occurrences of calls to `iter` or `into_iter` for the
/// given identifier
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
    let mut visitor = IterFunctionVisitor {
        uses: Vec::new(),
        target: identifier,
        seen_other: false,
    };
    visitor.visit_block(block);
    if visitor.seen_other { None } else { Some(visitor.uses) }
}
<commit_msg>needless_collect: use `node_type_opt` instead of `node_type`<commit_after>use super::NEEDLESS_COLLECT;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{is_trait_method, path_to_local_id, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
use rustc_lint::LateContext;
use rustc_middle::hir::map::Map;

use rustc_span::symbol::{sym, Ident};
use rustc_span::{MultiSpan, Span};

const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";

pub(super) fn check<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    check_needless_collect_direct_usage(expr, cx);
    check_needless_collect_indirect_usage(expr, cx);
}
fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    if_chain! {
        if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
        if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
        if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
        if let Some(generic_args) = chain_method.args;
        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
        if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
        if is_type_diagnostic_item(cx, ty, sym::vec_type)
            || is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
            || match_type(cx, ty, &paths::BTREEMAP)
            || is_type_diagnostic_item(cx, ty, sym::hashmap_type);
        if let Some(sugg) = match &*method.ident.name.as_str() {
            "len" => Some("count()".to_string()),
            "is_empty" => Some("next().is_none()".to_string()),
            "contains" => {
                let contains_arg = snippet(cx, args[1].span, "??");
                let (arg, pred) = contains_arg
                    .strip_prefix('&')
                    .map_or(("&x", &*contains_arg), |s| ("x", s));
                Some(format!("any(|{}| x == {})", arg, pred))
            }
            _ => None,
        };
        then {
            span_lint_and_sugg(
                cx,
                NEEDLESS_COLLECT,
                method0_span.with_hi(expr.span.hi()),
                NEEDLESS_COLLECT_MSG,
                "replace with",
                sugg,
                Applicability::MachineApplicable,
            );
        }
    }
}

fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
    fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
        if let Some(ty) = ty {
            return Some(ty.hir_id);
        }

        if let Some(generic_args) = method_args {
            if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
                return Some(ty.hir_id);
            }
        }

        None
    }
    if let ExprKind::Block(block, _) = expr.kind {
        for stmt in block.stmts {
            if_chain! {
                if let StmtKind::Local(
                    Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
                    init: Some(init_expr), ty, .. }
                ) = stmt.kind;
                if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
                if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
                if let Some(hir_id) = get_hir_id(*ty, method_name.args);
                if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
                if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                    is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                    is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
                    match_type(cx, ty, &paths::LINKED_LIST);
                if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                if let [iter_call] = &*iter_calls;
                then {
                    let mut used_count_visitor = UsedCountVisitor {
                        cx,
                        id: *pat_id,
                        count: 0,
                    };
                    walk_block(&mut used_count_visitor, block);
                    if used_count_visitor.count > 1 {
                        return;
                    }

                    // Suggest replacing iter_call with iter_replacement, and removing stmt
                    let mut span = MultiSpan::from_span(collect_span);
                    span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
                    span_lint_and_then(
                        cx,
                        super::NEEDLESS_COLLECT,
                        span,
                        NEEDLESS_COLLECT_MSG,
                        |diag| {
                            let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_source, ".."), iter_call.get_iter_method(cx));
                            diag.multipart_suggestion(
                                iter_call.get_suggestion_text(),
                                vec![
                                    (stmt.span, String::new()),
                                    (iter_call.span, iter_replacement)
                                ],
                                Applicability::MachineApplicable,// MaybeIncorrect,
                            );
                        },
                    );
                }
            }
        }
    }
}

struct IterFunction {
    func: IterFunctionKind,
    span: Span,
}
impl IterFunction {
    fn get_iter_method(&self, cx: &LateContext<'_>) -> String {
        match &self.func {
            IterFunctionKind::IntoIter => String::new(),
            IterFunctionKind::Len => String::from(".count()"),
            IterFunctionKind::IsEmpty => String::from(".next().is_none()"),
            IterFunctionKind::Contains(span) => {
                let s = snippet(cx, *span, "..");
                if let Some(stripped) = s.strip_prefix('&') {
                    format!(".any(|x| x == {})", stripped)
                } else {
                    format!(".any(|x| x == *{})", s)
                }
            },
        }
    }
    fn get_suggestion_text(&self) -> &'static str {
        match &self.func {
            IterFunctionKind::IntoIter => {
                "use the original Iterator instead of collecting it and then producing a new one"
            },
            IterFunctionKind::Len => {
                "take the original Iterator's count instead of collecting it and finding the length"
            },
            IterFunctionKind::IsEmpty => {
                "check if the original Iterator has anything instead of collecting it and seeing if it's empty"
            },
            IterFunctionKind::Contains(_) => {
                "check if the original Iterator contains an element instead of collecting then checking"
            },
        }
    }
}
enum IterFunctionKind {
    IntoIter,
    Len,
    IsEmpty,
    Contains(Span),
}

struct IterFunctionVisitor {
    uses: Vec<IterFunction>,
    seen_other: bool,
    target: Ident,
}
impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
        // Check function calls on our collection
        if_chain! {
            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                let len = sym!(len);
                let is_empty = sym!(is_empty);
                let contains = sym!(contains);
                match method_name.ident.name {
                    sym::into_iter => self.uses.push(
                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
                    ),
                    name if name == len => self.uses.push(
                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
                    ),
                    name if name == is_empty => self.uses.push(
                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
                    ),
                    name if name == contains => self.uses.push(
                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
                    ),
                    _ => self.seen_other = true,
                }
                return
            }
        }
        // Check if the collection is used for anything else
        if_chain! {
            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
            if let &[name] = &path.segments;
            if name.ident == self.target;
            then {
                self.seen_other = true;
            } else {
                walk_expr(self, expr);
            }
        }
    }

    type Map = Map<'tcx>;
    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}

struct UsedCountVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    id: HirId,
    count: usize,
}

impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if path_to_local_id(expr, self.id) {
            self.count += 1;
        } else {
            walk_expr(self, expr);
        }
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
    }
}

/// Detect the occurrences of calls to `iter` or `into_iter` for the
/// given identifier
fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
    let mut visitor = IterFunctionVisitor {
        uses: Vec::new(),
        target: identifier,
        seen_other: false,
    };
    visitor.visit_block(block);
    if visitor.seen_other { None } else { Some(visitor.uses) }
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;

use super::ITER_SKIP_NEXT;

pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
    // lint if caller of skip is an Iterator
    if is_trait_method(cx, expr, sym::Iterator) {
        if let [caller, n] = skip_args {
            let hint = format!(".nth({})", snippet(cx, n.span, ".."));
            span_lint_and_sugg(
                cx,
                ITER_SKIP_NEXT,
                expr.span.trim_start(caller.span).unwrap(),
                "called `skip(..).next()` on an iterator",
                "use `nth` instead",
                hint,
                Applicability::MachineApplicable,
            );
        }
    }
}
<commit_msg>remove a needless variable<commit_after>use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::sym;

use super::ITER_SKIP_NEXT;

pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
    // lint if caller of skip is an Iterator
    if is_trait_method(cx, expr, sym::Iterator) {
        if let [caller, n] = skip_args {
            span_lint_and_sugg(
                cx,
                ITER_SKIP_NEXT,
                expr.span.trim_start(caller.span).unwrap(),
                "called `skip(..).next()` on an iterator",
                "use `nth` instead",
                format!(".nth({})", snippet(cx, n.span, "..")),
                Applicability::MachineApplicable,
            );
        }
    }
}
<|endoftext|>


<commit_before>
use mqtt::ffiasync;
use eventual;

use std::mem;
use libc::{c_char, c_int, c_void};
use std::ffi::CString;
use std::ffi::CStr;
use std::ptr;
use std::slice;
use std::sync::Barrier;

pub enum PersistenceType {
    Default = 0,
    Nothing = 1,
    User    = 2,
}

#[derive(Debug)]
pub enum ConnectReturnCode {
    Success               = 0,
    UnacceptableProtocol  = 1,
    IdentifierRejected    = 2,
    ServerUnavailable     = 3,
    BadUsernameOrPassword = 4,
    NotAuthorized         = 5,
    Reserved              = 6,
}

#[derive(Debug)]
pub enum ConnectErr {
    ReturnCode(ConnectReturnCode),
    Callback
}

#[derive(Debug)]
pub enum MqttResult {
    Success,
    Error(i32),
}

#[derive(Debug)]
pub enum Qos {
    FireAndForget  = 0,
    AtLeastOnce    = 1,
    OnceAndOneOnly = 2,
}

pub struct AsyncClient {
    handle      : ffiasync::MQTTAsync,
    pub random  : i32,
    barrier     : Barrier
}
impl AsyncClient {

    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `context` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new(address: &str, clientid: &str, persistence: PersistenceType) -> Result<AsyncClient, MqttResult> {
        let mut handle                      = unsafe{mem::zeroed()};
        let mut persistence_context: c_void = unsafe{mem::zeroed()};

        let c_url          = CString::new(address).unwrap();
        let c_clientid     = CString::new(clientid).unwrap();
        let array_url      = c_url.as_bytes_with_nul();
        let array_clientid = c_clientid.as_bytes_with_nul();

        let mut error = unsafe {
            ffiasync::MQTTAsync_create(&mut handle,
                                       mem::transmute::<&u8, *const c_char>(&array_url[0]),
                                       mem::transmute::<&u8, *const c_char>(&array_clientid[0]),
                                       persistence as i32,
                                       &mut persistence_context)
        };

        match error {
            0   => { Ok( AsyncClient {
                        handle    : handle,
                        random    : 33,
                        barrier   : Barrier::new(2)
                    })},
            err => Err(MqttResult::Error(err))
        }
    }

    pub fn connect(&mut self, options: &mut AsyncConnectOptions) -> Result<(), ConnectErr> {
        unsafe {
            ffiasync::MQTTAsync_setCallbacks(self.handle,
                                             self.context(),
                                             Some(Self::disconnected),
                                             Some(Self::received),
                                             None);
        }

        // fill in FFI private struct
        options.options.keepAliveInterval = options.keep_alive_interval;
        options.options.cleansession      = options.cleansession;
        options.options.maxInflight       = options.max_in_flight;
        options.options.connectTimeout    = options.connect_timeout;
        options.options.retryInterval     = options.retry_interval;

        // register callbacks
        options.options.context   = self.context();
        options.options.onSuccess = Some(Self::connect_succeeded);
        options.options.onFailure = Some(Self::connect_failed);

        let mut error = unsafe {
            ffiasync::MQTTAsync_connect(self.handle, &options.options)
        };
        if error == 0 {
            self.barrier.wait();
            if self.is_connected() {
                Ok(())
            } else {
                Err(ConnectErr::Callback)
            }
        } else {
            Err(ConnectErr::ReturnCode(
                match error {
                    1 => ConnectReturnCode::UnacceptableProtocol,
                    2 => ConnectReturnCode::IdentifierRejected,
                    3 => ConnectReturnCode::ServerUnavailable,
                    4 => ConnectReturnCode::BadUsernameOrPassword,
                    5 => ConnectReturnCode::NotAuthorized,
                    _ => ConnectReturnCode::Reserved,
            }))
        }
    }

    extern "C" fn connect_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("connect succeeded");
        assert!(!context.is_null());

        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.barrier.wait();
        // selfclient.future.0.complete(42);
        selfclient.random = 69;
    }

    extern "C" fn connect_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        println!("connect failed");
        assert!(!context.is_null());
        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.barrier.wait();
    }

    extern "C" fn disconnected(context: *mut c_void, cause: *mut c_char) -> () {
        println!("disconnected");
        assert!(!context.is_null());
    }

    pub fn is_connected(&mut self) -> bool {
        let mut ret = unsafe {
            ffiasync::MQTTAsync_isConnected(self.handle)
        };

        match ret {
            1 => true,
            _ => false,
        }
    }

    pub fn send(&mut self, data: &[u8], topic: &str, qos: Qos) -> Result<(), MqttResult>{
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::send_succeeded),
            onFailure       : None,
            context         : self.context(),
            token           : 0,
        };

        let mut message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : data.len() as i32,
            payload         : unsafe {mem::transmute::<&u8, *mut c_void>(&data[0])},
            qos             : qos as c_int,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        let c_topic     = CString::new(topic).unwrap();
        let array_topic = c_topic.as_bytes_with_nul();

        let mut error = unsafe {
            ffiasync::MQTTAsync_sendMessage(self.handle,
                                            mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                            &mut message,
                                            &mut responseoption)
        };

        match error {
            0   => Ok(()),
            err => Err(MqttResult::Error(err)),
        }
    }

    extern "C" fn send_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("send succeeded");
        assert!(!context.is_null());
    }

    pub fn subscribe(&mut self, topic: &str, qos: Qos) -> Result<(), MqttResult> {
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::subscribe_succeeded),
            onFailure       : Some(Self::subscribe_failed),
            context         : self.context(),
            token           : 0,
        };

        let c_topic     = CString::new(topic).unwrap();
        let array_topic = c_topic.as_bytes_with_nul();

        let c_qos: i32 = match qos {
            Qos::FireAndForget  => 0,
            Qos::AtLeastOnce    => 1,
            Qos::OnceAndOneOnly => 2,
        };

        let mut error = unsafe {
            ffiasync::MQTTAsync_subscribe(self.handle,
                                          mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                          c_qos,
                                          &mut responseoption)
        };

        match error {
            0   => Ok(()),
            err => Err(MqttResult::Error(err)),
        }
    }

    extern "C" fn subscribe_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("subscribe succeeded");
        assert!(!context.is_null());
    }

    extern "C" fn subscribe_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        println!("subscribe failed");
        assert!(!context.is_null());
    }

    extern "C" fn received(context: *mut ::libc::c_void, topic_name: *mut ::libc::c_char, topic_len: ::libc::c_int, amessage: *mut ffiasync::MQTTAsync_message) -> i32 {
        let c_topic = unsafe {CStr::from_ptr(topic_name).to_bytes()};
        let topic   = String::from_utf8(c_topic.to_vec()).unwrap();
        assert_eq!(topic.len(), topic_len as usize);

        assert!(!amessage.is_null());
        let transmessage: &mut ffiasync::MQTTAsync_message = unsafe {mem::transmute(amessage)};
        let message: &[u8] = unsafe {
                slice::from_raw_parts(transmessage.payload as *mut u8, transmessage.payloadlen as usize)
        };

        let strmessage = String::from_utf8(message.to_vec()).unwrap();
        println!("received from topic: {}", topic);
        println!("       utf8 message: {}", strmessage);
        println!("        raw message: {:?}", message);

        let mut msg = amessage;
        unsafe{ffiasync::MQTTAsync_freeMessage(&mut msg)};
        unsafe{ffiasync::MQTTAsync_free(mem::transmute(topic_name))};

        1
    }
}

impl Drop for AsyncClient {
    fn drop(&mut self) {
        unsafe{ffiasync::MQTTAsync_destroy(&mut self.handle)};
    }
}

pub struct AsyncConnectOptions {
    options: ffiasync::MQTTAsync_connectOptions,

    pub keep_alive_interval : i32,
    pub cleansession        : i32,
    pub max_in_flight       : i32,
    pub connect_timeout     : i32,
    pub retry_interval      : i32,
}

impl AsyncConnectOptions {

    pub fn new() -> AsyncConnectOptions {
        let ffioptions = ffiasync::MQTTAsync_connectOptions {
            struct_id           : ['M' as i8, 'Q' as i8, 'T' as i8, 'C' as i8],
            struct_version      : 3,
            keepAliveInterval   : 60,
            cleansession        : 1,
            maxInflight         : 10,
            will                : ptr::null_mut(),
            username            : ptr::null_mut(),
            password            : ptr::null_mut(),
            connectTimeout      : 30,
            retryInterval       : 0,
            ssl                 : ptr::null_mut(),
            onSuccess           : None,
            onFailure           : None,
            context             : ptr::null_mut(),
            serverURIcount      : 0,
            serverURIs          : ptr::null_mut(),
            MQTTVersion         : 0,
        };

        let options = AsyncConnectOptions {
            options             : ffioptions,

            keep_alive_interval : 20,
            cleansession        : 1,
            max_in_flight       : 10,
            connect_timeout     : 30,
            retry_interval      : 0,
        };

        options
    }
}

pub struct AsyncDisconnectOptions {
    options: ffiasync::MQTTAsync_disconnectOptions,
}

impl AsyncDisconnectOptions {

    pub fn new() -> ffiasync::MQTTAsync_disconnectOptions {
        let options = ffiasync::MQTTAsync_disconnectOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'D' as i8],
            struct_version  : 0,
            timeout         : 0,
            onSuccess       : ptr::null_mut(),
            onFailure       : ptr::null_mut(),
            context         : ptr::null_mut(),
        };

        options
    }
}

pub struct AsyncMessage {
    options: ffiasync::MQTTAsync_message,
}

impl AsyncMessage {

    pub fn new() -> ffiasync::MQTTAsync_message {
        let message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : 0,
            payload         : ptr::null_mut(),
            qos             : 0,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        message
    }
}
<commit_msg>synchronous send<commit_after>use mqtt::ffiasync;

use libc::{c_char, c_int, c_void};
use std::ffi::{CStr, CString};
use std::mem;
use std::ptr;
use std::slice;
use std::sync::Barrier;

pub enum PersistenceType {
    Default = 0,
    Nothing = 1,
    User    = 2,
}

#[derive(Debug)]
pub enum ConnectReturnCode {
    Success               = 0,
    UnacceptableProtocol  = 1,
    IdentifierRejected    = 2,
    ServerUnavailable     = 3,
    BadUsernameOrPassword = 4,
    NotAuthorized         = 5,
    Reserved              = 6,
}

#[derive(Debug)]
pub enum ConnectErr {
    ReturnCode(ConnectReturnCode),
    Callback
}

#[derive(Debug, Copy, Clone)]
pub enum MqttError {
    Code(i32),
    Bad
}

#[derive(Debug)]
pub enum Qos {
    FireAndForget  = 0,
    AtLeastOnce    = 1,
    OnceAndOneOnly = 2,
}

#[derive(Debug, Copy, Clone)]
pub enum ActionResult {
    None,
    Ok,
    Err(MqttError)
}

pub struct AsyncClient {
    handle        : ffiasync::MQTTAsync,
    pub random    : i32,
    barrier       : Barrier,
    action_result : ActionResult
}
impl AsyncClient {

    /// Ensures the FFI struct is consistent for callback invocation.
    ///
    /// Because the user may move this struct, the `context` pointer
    /// passed back to FFI callbacks might be invalidated. This function
    /// should be called before FFI actions that might fire callbacks to ensure
    /// the self-pointer is valid.
    fn context(&mut self) -> *mut c_void {
        self as *mut _ as *mut c_void
    }

    pub fn new(address: &str, clientid: &str, persistence: PersistenceType) -> Result<AsyncClient, MqttError> {
        let mut handle                      = unsafe{mem::zeroed()};
        let mut persistence_context: c_void = unsafe{mem::zeroed()};

        let c_url          = CString::new(address).unwrap();
        let c_clientid     = CString::new(clientid).unwrap();
        let array_url      = c_url.as_bytes_with_nul();
        let array_clientid = c_clientid.as_bytes_with_nul();

        let mut error = unsafe {
            ffiasync::MQTTAsync_create(&mut handle,
                                       mem::transmute::<&u8, *const c_char>(&array_url[0]),
                                       mem::transmute::<&u8, *const c_char>(&array_clientid[0]),
                                       persistence as i32,
                                       &mut persistence_context)
        };

        match error {
            0   => { Ok( AsyncClient {
                        handle          : handle,
                        random          : 33,
                        barrier         : Barrier::new(2),
                        action_result   : ActionResult::None
                    })},
            err => Err(MqttError::Code(err))
        }
    }

    pub fn connect(&mut self, options: &mut AsyncConnectOptions) -> Result<(), ConnectErr> {
        unsafe {
            ffiasync::MQTTAsync_setCallbacks(self.handle,
                                             self.context(),
                                             Some(Self::disconnected),
                                             Some(Self::received),
                                             None);
        }

        // fill in FFI private struct
        options.options.keepAliveInterval = options.keep_alive_interval;
        options.options.cleansession      = options.cleansession;
        options.options.maxInflight       = options.max_in_flight;
        options.options.connectTimeout    = options.connect_timeout;
        options.options.retryInterval     = options.retry_interval;

        // register callbacks
        options.options.context   = self.context();
        options.options.onSuccess = Some(Self::connect_succeeded);
        options.options.onFailure = Some(Self::connect_failed);

        self.action_result = ActionResult::None;
        let mut error = unsafe {
            ffiasync::MQTTAsync_connect(self.handle, &options.options)
        };
        if error == 0 {
            self.barrier.wait();
            if self.is_connected() {
                Ok(())
            } else {
                Err(ConnectErr::Callback)
            }
        } else {
            Err(ConnectErr::ReturnCode(
                match error {
                    1 => ConnectReturnCode::UnacceptableProtocol,
                    2 => ConnectReturnCode::IdentifierRejected,
                    3 => ConnectReturnCode::ServerUnavailable,
                    4 => ConnectReturnCode::BadUsernameOrPassword,
                    5 => ConnectReturnCode::NotAuthorized,
                    _ => ConnectReturnCode::Reserved,
            }))
        }
    }

    extern "C" fn connect_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("connect succeeded");
        assert!(!context.is_null());

        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.action_result = ActionResult::Ok;
        selfclient.barrier.wait();
        selfclient.random = 69;
    }

    extern "C" fn connect_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        println!("connect failed");
        assert!(!context.is_null());
        let selfclient : &mut AsyncClient = unsafe {mem::transmute(context)};
        if response.is_null() {
            selfclient.action_result = ActionResult::Err(MqttError::Bad);
        } else {
            let resp : &mut ffiasync::MQTTAsync_failureData = unsafe {mem::transmute(response)};
            selfclient.action_result = ActionResult::Err(MqttError::Code(resp.code));
        }
        selfclient.barrier.wait();
    }

    extern "C" fn disconnected(context: *mut c_void, cause: *mut c_char) -> () {
        println!("disconnected");
        assert!(!context.is_null());
    }

    pub fn is_connected(&mut self) -> bool {
        let mut ret = unsafe {
            ffiasync::MQTTAsync_isConnected(self.handle)
        };

        match ret {
            1 => true,
            _ => false,
        }
    }

    pub fn send(&mut self, data: &[u8], topic: &str, qos: Qos) -> Result<(), MqttError>{
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::send_succeeded),
            onFailure       : Some(Self::send_failed),
            context         : self.context(),
            token           : 0,
        };

        let mut message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : data.len() as i32,
            payload         : unsafe {mem::transmute::<&u8, *mut c_void>(&data[0])},
            qos             : qos as c_int,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        let c_topic        = CString::new(topic).unwrap();
        let array_topic    = c_topic.as_bytes_with_nul();
        self.action_result = ActionResult::None;

        let mut error = unsafe {
            ffiasync::MQTTAsync_sendMessage(self.handle,
                                            mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                            &mut message,
                                            &mut responseoption)
        };
        if error == 0 {
            self.barrier.wait();
            match self.action_result {
                ActionResult::None   => unreachable!(),
                ActionResult::Ok     => Ok(()),
                ActionResult::Err(x) => Err(x)
            }
        } else { Err(MqttError::Code(error)) }
    }

    extern "C" fn send_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("send succeeded");
        assert!(!context.is_null());
        let selfclient: &mut AsyncClient = unsafe {mem::transmute(context)};
        selfclient.action_result = ActionResult::Ok;
        selfclient.barrier.wait();
    }

    extern "C" fn send_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        println!("send failed");
        assert!(!context.is_null());
        let selfclient : &mut AsyncClient                     = unsafe {mem::transmute(context)};
        if response.is_null() {
            selfclient.action_result = ActionResult::Err(MqttError::Bad);
        } else {
            let resp : &mut ffiasync::MQTTAsync_failureData = unsafe {mem::transmute(response)};
            selfclient.action_result = ActionResult::Err(MqttError::Code(resp.code));
        }
        selfclient.barrier.wait();
    }

    pub fn subscribe(&mut self, topic: &str, qos: Qos) -> Result<(), MqttError> {
        let mut responseoption = ffiasync::MQTTAsync_responseOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'R' as i8],
            struct_version  : 0,
            onSuccess       : Some(Self::subscribe_succeeded),
            onFailure       : Some(Self::subscribe_failed),
            context         : self.context(),
            token           : 0,
        };

        let c_topic     = CString::new(topic).unwrap();
        let array_topic = c_topic.as_bytes_with_nul();

        let c_qos: i32 = match qos {
            Qos::FireAndForget  => 0,
            Qos::AtLeastOnce    => 1,
            Qos::OnceAndOneOnly => 2,
        };

        let mut error = unsafe {
            ffiasync::MQTTAsync_subscribe(self.handle,
                                          mem::transmute::<&u8, *const c_char>(&array_topic[0]),
                                          c_qos,
                                          &mut responseoption)
        };

        match error {
            0   => Ok(()),
            err => Err(MqttError::Code(err)),
        }
    }

    extern "C" fn subscribe_succeeded(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_successData) -> () {
        println!("subscribe succeeded");
        assert!(!context.is_null());
    }

    extern "C" fn subscribe_failed(context: *mut ::libc::c_void, response: *mut ffiasync::MQTTAsync_failureData) -> () {
        println!("subscribe failed");
        assert!(!context.is_null());
    }

    extern "C" fn received(context: *mut ::libc::c_void, topic_name: *mut ::libc::c_char, topic_len: ::libc::c_int, amessage: *mut ffiasync::MQTTAsync_message) -> i32 {
        let c_topic = unsafe {CStr::from_ptr(topic_name).to_bytes()};
        let topic   = String::from_utf8(c_topic.to_vec()).unwrap();
        assert_eq!(topic.len(), topic_len as usize);

        assert!(!amessage.is_null());
        let transmessage: &mut ffiasync::MQTTAsync_message = unsafe {mem::transmute(amessage)};
        let message: &[u8] = unsafe {
                slice::from_raw_parts(transmessage.payload as *mut u8, transmessage.payloadlen as usize)
        };

        let strmessage = String::from_utf8(message.to_vec()).unwrap();
        println!("received from topic: {}", topic);
        println!("       utf8 message: {}", strmessage);
        println!("        raw message: {:?}", message);

        let mut msg = amessage;
        unsafe{ffiasync::MQTTAsync_freeMessage(&mut msg)};
        unsafe{ffiasync::MQTTAsync_free(mem::transmute(topic_name))};

        1
    }
}

impl Drop for AsyncClient {
    fn drop(&mut self) {
        unsafe{ffiasync::MQTTAsync_destroy(&mut self.handle)};
    }
}

pub struct AsyncConnectOptions {
    options: ffiasync::MQTTAsync_connectOptions,

    pub keep_alive_interval : i32,
    pub cleansession        : i32,
    pub max_in_flight       : i32,
    pub connect_timeout     : i32,
    pub retry_interval      : i32,
}

impl AsyncConnectOptions {

    pub fn new() -> AsyncConnectOptions {
        let ffioptions = ffiasync::MQTTAsync_connectOptions {
            struct_id           : ['M' as i8, 'Q' as i8, 'T' as i8, 'C' as i8],
            struct_version      : 3,
            keepAliveInterval   : 60,
            cleansession        : 1,
            maxInflight         : 10,
            will                : ptr::null_mut(),
            username            : ptr::null_mut(),
            password            : ptr::null_mut(),
            connectTimeout      : 30,
            retryInterval       : 0,
            ssl                 : ptr::null_mut(),
            onSuccess           : None,
            onFailure           : None,
            context             : ptr::null_mut(),
            serverURIcount      : 0,
            serverURIs          : ptr::null_mut(),
            MQTTVersion         : 0,
        };

        let options = AsyncConnectOptions {
            options             : ffioptions,

            keep_alive_interval : 20,
            cleansession        : 1,
            max_in_flight       : 10,
            connect_timeout     : 30,
            retry_interval      : 0,
        };

        options
    }
}

pub struct AsyncDisconnectOptions {
    options: ffiasync::MQTTAsync_disconnectOptions,
}

impl AsyncDisconnectOptions {

    pub fn new() -> ffiasync::MQTTAsync_disconnectOptions {
        let options = ffiasync::MQTTAsync_disconnectOptions {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'D' as i8],
            struct_version  : 0,
            timeout         : 0,
            onSuccess       : ptr::null_mut(),
            onFailure       : ptr::null_mut(),
            context         : ptr::null_mut(),
        };

        options
    }
}

pub struct AsyncMessage {
    options: ffiasync::MQTTAsync_message,
}

impl AsyncMessage {

    pub fn new() -> ffiasync::MQTTAsync_message {
        let message = ffiasync::MQTTAsync_message {
            struct_id       : ['M' as i8, 'Q' as i8, 'T' as i8, 'M' as i8],
            struct_version  : 0,
            payloadlen      : 0,
            payload         : ptr::null_mut(),
            qos             : 0,
            retained        : 0,
            dup             : 0,
            msgid           : 0,
        };

        message
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;
use calculator_capnp::calculator;
use gj::Promise;

#[derive(Clone, Copy)]
pub struct PowerFunction;

impl calculator::function::Server for PowerFunction {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, ::capnp::Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(::capnp::Error::failed("Wrong number of parameters".to_string()))
        } else {
            results.get().set_value(params.get(0).powf(params.get(1)));
            Promise::ok(results)
        }
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    ::gj::EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let stream = try!(::gj::io::tcp::Stream::connect(addr).wait(wait_scope));
        let stream2 = try!(stream.try_clone());
        let connection: Box<::capnp_rpc::VatNetwork<twoparty::VatId>> =
            Box::new(twoparty::VatNetwork::new(stream, stream2,
                                               rpc_twoparty_capnp::Side::Client,
                                               Default::default()));
        let mut rpc_system = rpc::System::new(connection, None);
        let calculator = calculator::Client {
            client: rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server)
        };

        {
            println!("Evaluating a literal...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(11.0);
            try!(request.send().promise.then(|response| {
                let value = pry!(pry!(response.get()).get_value());
                let request = value.read_request();
                request.send().promise.then(|response|{
                    assert_eq!(pry!(response.get()).get_value(), 11.0);
                    Promise::ok(())
                })
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            println!("Evaluating a literal using pipelining...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(23.0);
            let value = request.send().pipeline.get_value();
            let request = value.read_request();
            try!(request.send().promise.then(|response|{
                assert_eq!(pry!(response.get()).get_value(), 23.0);
                Promise::ok(())
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            // Make a request to evaluate 123 + 45 - 67.
            //
            // The Calculator interface requires that we first call getOperator() to
            // get the addition and subtraction functions, then call evaluate() to use
            // them.  But, once again, we can get both functions, call evaluate(), and
            // then read() the result -- four RPCs -- in the time of *one* network
            // round trip, because of promise pipelining.

            println!("Using add and subtract... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let subtract = {
                // Get the "subtract" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Subtract);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 123 + 45 - 67.
            let mut request = calculator.evaluate_request();

            {
                let mut subtract_call = request.get().init_expression().init_call();
                subtract_call.set_function(subtract);
                let mut subtract_params = subtract_call.init_params(2);
                subtract_params.borrow().get(1).set_literal(67.0);

                let mut add_call = subtract_params.get(0).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(123.0);
                add_params.get(1).set_literal(45.0);
            }

            // Send the evaluate() request, read() the result, and wait for read() to
            // finish.
            let eval_promise = request.send();
            let read_promise = eval_promise.pipeline.get_value().read_request().send();

            let response = try!(read_promise.promise.wait(wait_scope));
            assert_eq!(try!(response.get()).get_value(), 101.0);

            println!("PASS");
        }

        {
            // Make a request to evaluate 4 * 6, then use the result in two more
            // requests that add 3 and 5.
            //
            // Since evaluate() returns its result wrapped in a `Value`, we can pass
            // that `Value` back to the server in subsequent requests before the first
            // `evaluate()` has actually returned.  Thus, this example again does only
            // one network round trip.

            println!("Pipelining eval() calls... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                // Get the "multiply" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 4 * 6
            let mut request = calculator.evaluate_request();

            {
                let mut multiply_call = request.get().init_expression().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_literal(4.0);
                multiply_params.borrow().get(1).set_literal(6.0);
            }

            let multiply_result = request.send().pipeline.get_value();

            // Use the result in two calls that add 3 and add 5.
            let mut add3_request = calculator.evaluate_request();
            {
                let mut add3_call = add3_request.get().init_expression().init_call();
                add3_call.set_function(add.clone());
                let mut add3_params = add3_call.init_params(2);
                add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
                add3_params.borrow().get(1).set_literal(3.0);
            }

            let add3_promise = add3_request.send().pipeline.get_value().read_request().send();

            let mut add5_request = calculator.evaluate_request();
            {
                let mut add5_call = add5_request.get().init_expression().init_call();
                add5_call.set_function(add);
                let mut add5_params = add5_call.init_params(2);
                add5_params.borrow().get(0).set_previous_result(multiply_result);
                add5_params.get(1).set_literal(5.0);
            }

            let add5_promise = add5_request.send().pipeline.get_value().read_request().send();

            // Now wait for the results.
            assert!(try!(try!(add3_promise.promise.wait(wait_scope)).get()).get_value() == 27.0);
            assert!(try!(try!(add5_promise.promise.wait(wait_scope)).get()).get_value() == 29.0);

            println!("PASS")
        }

        {
            // Our calculator interface supports defining functions.  Here we use it
            // to define two functions and then make calls to them as follows:
            //
            //   f(x, y) = x * 100 + y
            //   g(x) = f(x, x + 1) * 2;
            //   f(12, 34)
            //   g(21)
            //
            // Once again, the whole thing takes only one network round trip.

            println!("Defining functions... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            let f = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(2);
                    {
                        let mut add_call = def_function_params.init_body().init_call();
                        add_call.set_function(add.clone());
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(1).set_parameter(1);

                        let mut multiply_call = add_params.get(0).init_call();
                        multiply_call.set_function(multiply.clone());
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(0).set_parameter(0);
                        multiply_params.get(1).set_literal(100.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let g = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(1);
                    {
                        let mut multiply_call = def_function_params.init_body().init_call();
                        multiply_call.set_function(multiply);
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(1).set_literal(2.0);

                        let mut f_call = multiply_params.get(0).init_call();
                        f_call.set_function(f.clone());
                        let mut f_params = f_call.init_params(2);
                        f_params.borrow().get(0).set_parameter(0);

                        let mut add_call = f_params.get(1).init_call();
                        add_call.set_function(add);
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(0).set_parameter(0);
                        add_params.get(1).set_literal(1.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let mut f_eval_request = calculator.evaluate_request();
            {
                let mut f_call = f_eval_request.get().init_expression().init_call();
                f_call.set_function(f);
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_literal(12.0);
                f_params.get(1).set_literal(34.0);
            }
            let f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

            let mut g_eval_request = calculator.evaluate_request();
            {
                let mut g_call = g_eval_request.get().init_expression().init_call();
                g_call.set_function(g);
                g_call.init_params(1).get(0).set_literal(21.0);
            }
            let g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(f_eval_promise.promise.wait(wait_scope)).get()).get_value() == 1234.0);
            assert!(try!(try!(g_eval_promise.promise.wait(wait_scope)).get()).get_value() == 4244.0);

            println!("PASS")
        }

        {
            // Make a request that will call back to a function defined locally.
            //
            // Specifically, we will compute 2^(4 + 5).  However, exponent is not
            // defined by the Calculator server.  So, we'll implement the Function
            // interface locally and pass it to the server for it to use when
            // evaluating the expression.
            //
            // This example requires two network round trips to complete, because the
            // server calls back to the client once before finishing.  In this
            // particular case, this could potentially be optimized by using a tail
            // call on the server side -- see CallContext::tailCall().  However, to
            // keep the example simpler, we haven't implemented this optimization in
            // the sample server.

            println!("Using a callback... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let mut request = calculator.evaluate_request();
            {
                let mut pow_call = request.get().init_expression().init_call();
                pow_call.set_function(
                    calculator::function::ToClient::new(PowerFunction).from_server::<LocalClient>());
                let mut pow_params = pow_call.init_params(2);
                pow_params.borrow().get(0).set_literal(2.0);

                let mut add_call = pow_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(4.0);
                add_params.get(1).set_literal(5.0);
            }

            let response_promise = request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(response_promise.promise.wait(wait_scope)).get()).get_value() == 512.0);

            println!("PASS");
        }

        Ok(())
    }).expect("top level error");
}
<commit_msg>type annotation no longer needed<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use capnp_rpc::{rpc, twoparty, rpc_twoparty_capnp};
use capnp_rpc::rpc::LocalClient;
use calculator_capnp::calculator;
use gj::Promise;

#[derive(Clone, Copy)]
pub struct PowerFunction;

impl calculator::function::Server for PowerFunction {
    fn call(&mut self,
            params: calculator::function::CallParams,
            mut results: calculator::function::CallResults)
        -> Promise<calculator::function::CallResults, ::capnp::Error>
    {
        let params = pry!(params.get().get_params());
        if params.len() != 2 {
            Promise::err(::capnp::Error::failed("Wrong number of parameters".to_string()))
        } else {
            results.get().set_value(params.get(0).powf(params.get(1)));
            Promise::ok(results)
        }
    }
}

pub fn main() {
    let args: Vec<String> = ::std::env::args().collect();
    if args.len() != 3 {
        println!("usage: {} client HOST:PORT", args[0]);
        return;
    }

    ::gj::EventLoop::top_level(move |wait_scope| {
        use std::net::ToSocketAddrs;
        let addr = try!(args[2].to_socket_addrs()).next().expect("could not parse address");
        let stream = try!(::gj::io::tcp::Stream::connect(addr).wait(wait_scope));
        let stream2 = try!(stream.try_clone());
        let network =
            Box::new(twoparty::VatNetwork::new(stream, stream2,
                                               rpc_twoparty_capnp::Side::Client,
                                               Default::default()));
        let mut rpc_system = rpc::System::new(network, None);
        let calculator = calculator::Client {
            client: rpc_system.bootstrap(rpc_twoparty_capnp::Side::Server)
        };

        {
            println!("Evaluating a literal...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(11.0);
            try!(request.send().promise.then(|response| {
                let value = pry!(pry!(response.get()).get_value());
                let request = value.read_request();
                request.send().promise.then(|response|{
                    assert_eq!(pry!(response.get()).get_value(), 11.0);
                    Promise::ok(())
                })
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            println!("Evaluating a literal using pipelining...");
            let mut request = calculator.evaluate_request();
            request.get().init_expression().set_literal(23.0);
            let value = request.send().pipeline.get_value();
            let request = value.read_request();
            try!(request.send().promise.then(|response|{
                assert_eq!(pry!(response.get()).get_value(), 23.0);
                Promise::ok(())
            }).wait(wait_scope));
            println!("PASS");
        }

        {
            // Make a request to evaluate 123 + 45 - 67.
            //
            // The Calculator interface requires that we first call getOperator() to
            // get the addition and subtraction functions, then call evaluate() to use
            // them.  But, once again, we can get both functions, call evaluate(), and
            // then read() the result -- four RPCs -- in the time of *one* network
            // round trip, because of promise pipelining.

            println!("Using add and subtract... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let subtract = {
                // Get the "subtract" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Subtract);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 123 + 45 - 67.
            let mut request = calculator.evaluate_request();

            {
                let mut subtract_call = request.get().init_expression().init_call();
                subtract_call.set_function(subtract);
                let mut subtract_params = subtract_call.init_params(2);
                subtract_params.borrow().get(1).set_literal(67.0);

                let mut add_call = subtract_params.get(0).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(123.0);
                add_params.get(1).set_literal(45.0);
            }

            // Send the evaluate() request, read() the result, and wait for read() to
            // finish.
            let eval_promise = request.send();
            let read_promise = eval_promise.pipeline.get_value().read_request().send();

            let response = try!(read_promise.promise.wait(wait_scope));
            assert_eq!(try!(response.get()).get_value(), 101.0);

            println!("PASS");
        }

        {
            // Make a request to evaluate 4 * 6, then use the result in two more
            // requests that add 3 and 5.
            //
            // Since evaluate() returns its result wrapped in a `Value`, we can pass
            // that `Value` back to the server in subsequent requests before the first
            // `evaluate()` has actually returned.  Thus, this example again does only
            // one network round trip.

            println!("Pipelining eval() calls... ");

            let add = {
                // Get the "add" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                // Get the "multiply" function from the server.
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            // Build the request to evaluate 4 * 6
            let mut request = calculator.evaluate_request();

            {
                let mut multiply_call = request.get().init_expression().init_call();
                multiply_call.set_function(multiply);
                let mut multiply_params = multiply_call.init_params(2);
                multiply_params.borrow().get(0).set_literal(4.0);
                multiply_params.borrow().get(1).set_literal(6.0);
            }

            let multiply_result = request.send().pipeline.get_value();

            // Use the result in two calls that add 3 and add 5.
            let mut add3_request = calculator.evaluate_request();
            {
                let mut add3_call = add3_request.get().init_expression().init_call();
                add3_call.set_function(add.clone());
                let mut add3_params = add3_call.init_params(2);
                add3_params.borrow().get(0).set_previous_result(multiply_result.clone());
                add3_params.borrow().get(1).set_literal(3.0);
            }

            let add3_promise = add3_request.send().pipeline.get_value().read_request().send();

            let mut add5_request = calculator.evaluate_request();
            {
                let mut add5_call = add5_request.get().init_expression().init_call();
                add5_call.set_function(add);
                let mut add5_params = add5_call.init_params(2);
                add5_params.borrow().get(0).set_previous_result(multiply_result);
                add5_params.get(1).set_literal(5.0);
            }

            let add5_promise = add5_request.send().pipeline.get_value().read_request().send();

            // Now wait for the results.
            assert!(try!(try!(add3_promise.promise.wait(wait_scope)).get()).get_value() == 27.0);
            assert!(try!(try!(add5_promise.promise.wait(wait_scope)).get()).get_value() == 29.0);

            println!("PASS")
        }

        {
            // Our calculator interface supports defining functions.  Here we use it
            // to define two functions and then make calls to them as follows:
            //
            //   f(x, y) = x * 100 + y
            //   g(x) = f(x, x + 1) * 2;
            //   f(12, 34)
            //   g(21)
            //
            // Once again, the whole thing takes only one network round trip.

            println!("Defining functions... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let multiply = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Multiply);
                request.send().pipeline.get_func()
            };

            let f = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(2);
                    {
                        let mut add_call = def_function_params.init_body().init_call();
                        add_call.set_function(add.clone());
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(1).set_parameter(1);

                        let mut multiply_call = add_params.get(0).init_call();
                        multiply_call.set_function(multiply.clone());
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(0).set_parameter(0);
                        multiply_params.get(1).set_literal(100.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let g = {
                let mut request = calculator.def_function_request();
                {
                    let mut def_function_params = request.get();
                    def_function_params.set_param_count(1);
                    {
                        let mut multiply_call = def_function_params.init_body().init_call();
                        multiply_call.set_function(multiply);
                        let mut multiply_params = multiply_call.init_params(2);
                        multiply_params.borrow().get(1).set_literal(2.0);

                        let mut f_call = multiply_params.get(0).init_call();
                        f_call.set_function(f.clone());
                        let mut f_params = f_call.init_params(2);
                        f_params.borrow().get(0).set_parameter(0);

                        let mut add_call = f_params.get(1).init_call();
                        add_call.set_function(add);
                        let mut add_params = add_call.init_params(2);
                        add_params.borrow().get(0).set_parameter(0);
                        add_params.get(1).set_literal(1.0);
                    }
                }
                request.send().pipeline.get_func()
            };

            let mut f_eval_request = calculator.evaluate_request();
            {
                let mut f_call = f_eval_request.get().init_expression().init_call();
                f_call.set_function(f);
                let mut f_params = f_call.init_params(2);
                f_params.borrow().get(0).set_literal(12.0);
                f_params.get(1).set_literal(34.0);
            }
            let f_eval_promise = f_eval_request.send().pipeline.get_value().read_request().send();

            let mut g_eval_request = calculator.evaluate_request();
            {
                let mut g_call = g_eval_request.get().init_expression().init_call();
                g_call.set_function(g);
                g_call.init_params(1).get(0).set_literal(21.0);
            }
            let g_eval_promise = g_eval_request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(f_eval_promise.promise.wait(wait_scope)).get()).get_value() == 1234.0);
            assert!(try!(try!(g_eval_promise.promise.wait(wait_scope)).get()).get_value() == 4244.0);

            println!("PASS")
        }

        {
            // Make a request that will call back to a function defined locally.
            //
            // Specifically, we will compute 2^(4 + 5).  However, exponent is not
            // defined by the Calculator server.  So, we'll implement the Function
            // interface locally and pass it to the server for it to use when
            // evaluating the expression.
            //
            // This example requires two network round trips to complete, because the
            // server calls back to the client once before finishing.  In this
            // particular case, this could potentially be optimized by using a tail
            // call on the server side -- see CallContext::tailCall().  However, to
            // keep the example simpler, we haven't implemented this optimization in
            // the sample server.

            println!("Using a callback... ");

            let add = {
                let mut request = calculator.get_operator_request();
                request.get().set_op(calculator::Operator::Add);
                request.send().pipeline.get_func()
            };

            let mut request = calculator.evaluate_request();
            {
                let mut pow_call = request.get().init_expression().init_call();
                pow_call.set_function(
                    calculator::function::ToClient::new(PowerFunction).from_server::<LocalClient>());
                let mut pow_params = pow_call.init_params(2);
                pow_params.borrow().get(0).set_literal(2.0);

                let mut add_call = pow_params.get(1).init_call();
                add_call.set_function(add);
                let mut add_params = add_call.init_params(2);
                add_params.borrow().get(0).set_literal(4.0);
                add_params.get(1).set_literal(5.0);
            }

            let response_promise = request.send().pipeline.get_value().read_request().send();

            assert!(try!(try!(response_promise.promise.wait(wait_scope)).get()).get_value() == 512.0);

            println!("PASS");
        }

        Ok(())
    }).expect("top level error");
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor::DescriptorDesc;
use device::Device;

/// Describes the layout of all descriptors within a descriptor set.
///
/// Despite its name, this type is technically not unsafe. However it serves the same purpose
/// in the API as other types whose names start with `Unsafe`.
pub struct UnsafeDescriptorSetLayout {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
}

impl UnsafeDescriptorSetLayout {
    /// Builds a new `UnsafeDescriptorSetLayout` with the given descriptors.
    pub fn new<I>(device: &Arc<Device>, descriptors: I)
                  -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
        where I: IntoIterator<Item = DescriptorDesc>
    {
        let vk = device.pointers();

        let bindings = descriptors.into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<SmallVec<[_; 32]>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(UnsafeDescriptorSetLayout {
            layout: layout,
            device: device.clone(),
        }))
    }

    /// Returns the device used to create this layout.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl Drop for UnsafeDescriptorSetLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout,
                                          ptr::null());
        }
    }
}
<commit_msg>Minor documentation and test for unsafe descriptor set layout<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::mem;
use std::ptr;
use std::sync::Arc;
use smallvec::SmallVec;

use check_errors;
use OomError;
use VulkanObject;
use VulkanPointers;
use vk;

use descriptor::descriptor::DescriptorDesc;
use device::Device;

/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
///
/// Despite its name, this type is technically not unsafe. However it serves the same purpose
/// in the API as other types whose names start with `Unsafe`.
pub struct UnsafeDescriptorSetLayout {
    layout: vk::DescriptorSetLayout,
    device: Arc<Device>,
}

impl UnsafeDescriptorSetLayout {
    /// Builds a new `UnsafeDescriptorSetLayout` with the given descriptors.
    pub fn new<I>(device: &Arc<Device>, descriptors: I)
                  -> Result<Arc<UnsafeDescriptorSetLayout>, OomError>
        where I: IntoIterator<Item = DescriptorDesc>
    {
        let vk = device.pointers();

        let bindings = descriptors.into_iter().map(|desc| {
            vk::DescriptorSetLayoutBinding {
                binding: desc.binding,
                descriptorType: desc.ty.vk_enum(),
                descriptorCount: desc.array_count,
                stageFlags: desc.stages.into(),
                pImmutableSamplers: ptr::null(),        // FIXME: not yet implemented
            }
        }).collect::<SmallVec<[_; 32]>>();

        let layout = unsafe {
            let infos = vk::DescriptorSetLayoutCreateInfo {
                sType: vk::STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
                pNext: ptr::null(),
                flags: 0,   // reserved
                bindingCount: bindings.len() as u32,
                pBindings: bindings.as_ptr(),
            };

            let mut output = mem::uninitialized();
            try!(check_errors(vk.CreateDescriptorSetLayout(device.internal_object(), &infos,
                                                           ptr::null(), &mut output)));
            output
        };

        Ok(Arc::new(UnsafeDescriptorSetLayout {
            layout: layout,
            device: device.clone(),
        }))
    }

    /// Returns the device used to create this layout.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

unsafe impl VulkanObject for UnsafeDescriptorSetLayout {
    type Object = vk::DescriptorSetLayout;

    #[inline]
    fn internal_object(&self) -> vk::DescriptorSetLayout {
        self.layout
    }
}

impl Drop for UnsafeDescriptorSetLayout {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            let vk = self.device.pointers();
            vk.DestroyDescriptorSetLayout(self.device.internal_object(), self.layout,
                                          ptr::null());
        }
    }
}

#[cfg(test)]
mod tests {
    use std::iter;
    use descriptor::descriptor_set::unsafe_layout::UnsafeDescriptorSetLayout;

    #[test]
    fn empty() {
        let (device, _) = gfx_dev_and_queue!();
        let _layout = UnsafeDescriptorSetLayout::new(&device, iter::empty());
    }
}
<|endoftext|>


<commit_before>use super::{MAX_VAL, MAX_SUM, Cand, CAND_ALL};

// (length, sum, available vals) -> (imperative vals, allowed vals)
pub struct Dictionary {
    data: Vec<(Cand, Cand)>,
}
pub const IMPOSSIBLE: (Cand, Cand) = (CAND_ALL, 0);

impl Dictionary {
    pub fn at(&self, len: i32, sum: i32, available: Cand) -> (Cand, Cand) {
        self.data[(((len * (MAX_SUM + 1) + sum) << MAX_VAL) | available as i32) as usize]
    }
    pub fn imperative(&self, len: i32, sum: i32, available: Cand) -> Cand {
        self.at(len, sum, available).0
    }
    pub fn allowed(&self, len: i32, sum: i32, available: Cand) -> Cand {
        self.at(len, sum, available).1
    }

    pub fn default() -> Dictionary {
        let mut data = vec![IMPOSSIBLE; ((MAX_VAL + 1) * (MAX_SUM + 1) * (1 << MAX_VAL as i32)) as usize];
        for vals in 0..(1 << MAX_VAL) {
            data[vals] = (0, 0);
        }

        for len in 1..(MAX_VAL + 1) {
            for sum in 1..(MAX_SUM + 1) {
                for vals in 0..(1 << MAX_VAL) {
                    let mut imperative = CAND_ALL;
                    let mut allowed = 0;
                    for i in 1..(MAX_VAL + 1) {
                        if (vals & (1 << (i - 1))) != 0 && sum >= i {
                            let nxt = data[(((len - 1) * (MAX_SUM + 1) + (sum - i) << MAX_VAL) | (vals ^ (1 << (i - 1)))) as usize];
                            if nxt != IMPOSSIBLE {
                                imperative &= nxt.0 | (1 << (i - 1));
                                allowed |= nxt.1 | (1 << (i - 1));
                            }
                        }
                    }
                    data[(((len * (MAX_SUM + 1) + sum) << MAX_VAL) | vals) as usize] = (imperative, allowed);
                }
            }
        }
        Dictionary {
            data: data
        }
    }
}

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

    #[test]
    fn test_dictionary_default() {
        let dic = Dictionary::default();

        assert_eq!(dic.at(1,  0, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(1,  1, CAND_ALL), (0b000000001, 0b000000001));
        assert_eq!(dic.at(1,  8, CAND_ALL), (0b010000000, 0b010000000));
        assert_eq!(dic.at(1,  9, CAND_ALL), (0b100000000, 0b100000000));
        assert_eq!(dic.at(1, 10, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(2,  2, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(2,  3, CAND_ALL), (0b000000011, 0b000000011));
        assert_eq!(dic.at(2,  4, CAND_ALL), (0b000000101, 0b000000101));
        assert_eq!(dic.at(2,  5, CAND_ALL), (0b000000000, 0b000001111));
        assert_eq!(dic.at(2, 16, CAND_ALL), (0b101000000, 0b101000000));
        assert_eq!(dic.at(2, 17, CAND_ALL), (0b110000000, 0b110000000));
        assert_eq!(dic.at(2, 18, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(3,  7, CAND_ALL), (0b000001011, 0b000001011));
        assert_eq!(dic.at(3,  8, CAND_ALL), (0b000000001, 0b000011111));
        assert_eq!(dic.at(3, 24, CAND_ALL), (0b111000000, 0b111000000));
        assert_eq!(dic.at(4, 10, CAND_ALL), (0b000001111, 0b000001111));
        assert_eq!(dic.at(4, 12, CAND_ALL), (0b000000011, 0b000111111));
        assert_eq!(dic.at(9, 44, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(9, 45, CAND_ALL), (0b111111111, 0b111111111));
    }
}
<commit_msg>Kakuro: add dictionary generator which uses only limited techniques<commit_after>use super::{MAX_VAL, MAX_SUM, Cand, CAND_ALL};

// (length, sum, available vals) -> (imperative vals, allowed vals)
pub struct Dictionary {
    data: Vec<(Cand, Cand)>,
}
pub const IMPOSSIBLE: (Cand, Cand) = (CAND_ALL, 0);

impl Dictionary {
    pub fn at(&self, len: i32, sum: i32, available: Cand) -> (Cand, Cand) {
        self.data[(((len * (MAX_SUM + 1) + sum) << MAX_VAL) | available as i32) as usize]
    }
    pub fn imperative(&self, len: i32, sum: i32, available: Cand) -> Cand {
        self.at(len, sum, available).0
    }
    pub fn allowed(&self, len: i32, sum: i32, available: Cand) -> Cand {
        self.at(len, sum, available).1
    }

    pub fn default() -> Dictionary {
        let mut data = vec![IMPOSSIBLE; ((MAX_VAL + 1) * (MAX_SUM + 1) * (1 << MAX_VAL as i32)) as usize];
        for vals in 0..(1 << MAX_VAL) {
            data[vals] = (0, 0);
        }

        for len in 1..(MAX_VAL + 1) {
            for sum in 1..(MAX_SUM + 1) {
                for vals in 0..(1 << MAX_VAL) {
                    let mut imperative = CAND_ALL;
                    let mut allowed = 0;
                    for i in 1..(MAX_VAL + 1) {
                        if (vals & (1 << (i - 1))) != 0 && sum >= i {
                            let nxt = data[(((len - 1) * (MAX_SUM + 1) + (sum - i) << MAX_VAL) | (vals ^ (1 << (i - 1)))) as usize];
                            if nxt != IMPOSSIBLE {
                                imperative &= nxt.0 | (1 << (i - 1));
                                allowed |= nxt.1 | (1 << (i - 1));
                            }
                        }
                    }
                    data[(((len * (MAX_SUM + 1) + sum) << MAX_VAL) | vals) as usize] = (imperative, allowed);
                }
            }
        }
        Dictionary {
            data: data
        }
    }
    pub fn limited() -> Dictionary {
        let mut data = vec![IMPOSSIBLE; ((MAX_VAL + 1) * (MAX_SUM + 1) * (1 << MAX_VAL as i32)) as usize];
        for vals in 0..(1 << MAX_VAL) {
            data[vals] = (0, 0);
        }
        for len in 1..(MAX_VAL + 1) {
            for sum in 1..(MAX_SUM + 1) {
                for vals in 0..((1 as Cand) << MAX_VAL) {
                    if vals.count_ones() < len as u32 { continue; }

                    let mut cand = vec![];
                    for i in 1..(MAX_VAL + 1) {
                        if (vals & (1 << (i - 1))) != 0 {
                            cand.push(i);
                        }
                    }
                    let mut imperative = 0;
                    let mut allowed = vals;

                    let mut sum_low: i32 = 0;
                    for i in 0..(len - 1)  {
                        sum_low += cand[i as usize];
                    }
                    let high_max = sum - sum_low;
                    if high_max < cand[(len - 1) as usize] { continue; }
                    if high_max < MAX_VAL {
                        allowed &= (1 << (high_max as Cand)) - 1;
                    }
                    if high_max == cand[(len - 1) as usize] + 1 {
                        allowed &= !(1 << (high_max as Cand - 2));
                    }

                    cand.reverse();
                    let mut sum_high: i32 = 0;
                    for i in 0..(len - 1)  {
                        sum_high += cand[i as usize];
                    }
                    let low_min = sum - sum_high;
                    if low_min > cand[(len - 1) as usize] { continue; }
                    if low_min > 1 {
                        allowed &= !((1 << (low_min as Cand - 1)) - 1);
                    }
                    if low_min == cand[(len - 1) as usize] - 1 {
                        allowed &= !(1 << (low_min as Cand));
                    }
                    data[(((len * (MAX_SUM + 1) + sum) << MAX_VAL) | (vals as i32)) as usize] = (imperative, allowed);
                }
            }
        }
        Dictionary {
            data: data
        }
    }
}

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

    #[test]
    fn test_dictionary_default() {
        let dic = Dictionary::default();

        assert_eq!(dic.at(1,  0, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(1,  1, CAND_ALL), (0b000000001, 0b000000001));
        assert_eq!(dic.at(1,  8, CAND_ALL), (0b010000000, 0b010000000));
        assert_eq!(dic.at(1,  9, CAND_ALL), (0b100000000, 0b100000000));
        assert_eq!(dic.at(1, 10, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(2,  2, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(2,  3, CAND_ALL), (0b000000011, 0b000000011));
        assert_eq!(dic.at(2,  4, CAND_ALL), (0b000000101, 0b000000101));
        assert_eq!(dic.at(2,  5, CAND_ALL), (0b000000000, 0b000001111));
        assert_eq!(dic.at(2, 16, CAND_ALL), (0b101000000, 0b101000000));
        assert_eq!(dic.at(2, 17, CAND_ALL), (0b110000000, 0b110000000));
        assert_eq!(dic.at(2, 18, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(3,  7, CAND_ALL), (0b000001011, 0b000001011));
        assert_eq!(dic.at(3,  8, CAND_ALL), (0b000000001, 0b000011111));
        assert_eq!(dic.at(3, 24, CAND_ALL), (0b111000000, 0b111000000));
        assert_eq!(dic.at(4, 10, CAND_ALL), (0b000001111, 0b000001111));
        assert_eq!(dic.at(4, 12, CAND_ALL), (0b000000011, 0b000111111));
        assert_eq!(dic.at(9, 44, CAND_ALL), IMPOSSIBLE);
        assert_eq!(dic.at(9, 45, CAND_ALL), (0b111111111, 0b111111111));
    }

    #[test]
    fn test_dictionary_limited_soundness() {
        let dic_default = Dictionary::default();
        let dic_limited = Dictionary::limited();

        for len in 0..(MAX_VAL + 1) {
            for sum in 1..(MAX_SUM + 1) {
                for vals in 0..(1 << MAX_VAL) {
                    let (imperative, allowed) = dic_default.at(len, sum, vals);
                    let (imperative_lim, allowed_lim) = dic_limited.at(len, sum, vals);

                    if (imperative_lim, allowed_lim) == IMPOSSIBLE {
                        assert_eq!((imperative, allowed), IMPOSSIBLE);
                    }
                    assert_eq!(imperative & imperative_lim, imperative_lim);
                    assert_eq!(allowed & allowed_lim, allowed);
                }
            }
        }
    }
}
<|endoftext|>