<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashSet;

use proc_macro2::TokenStream;
use quote::quote;
use syn::{
    parse::Parser,
    parse_quote,
    punctuated::Punctuated,
    token::{Comma, Unsafe},
    Attribute, FnArg, ForeignItem, Ident, ImplItem, Item, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    ImplBlockDetails, RsCodegenResult, TraitImplBlockDetails, Use,
};
use crate::{
    conversion::{
        analysis::fun::{
            ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
            TraitMethodDetails,
        },
        api::UnsafetyNeeded,
    },
    types::{Namespace, QualifiedName},
};
use crate::{
    conversion::{api::FuncToConvert, codegen_rs::lifetime::add_explicit_lifetime_if_necessary},
    types::make_ident,
};

impl UnsafetyNeeded {
    pub(crate) fn bridge_token(&self) -> Option<Unsafe> {
        match self {
            UnsafetyNeeded::None => None,
            _ => Some(parse_quote! { unsafe }),
        }
    }

    pub(crate) fn wrapper_token(&self) -> Option<Unsafe> {
        match self {
            UnsafetyNeeded::Always => Some(parse_quote! { unsafe }),
            _ => None,
        }
    }

    pub(crate) fn from_param_details(params: &[ArgumentAnalysis], ignore_receiver: bool) -> Self {
        params.iter().fold(UnsafetyNeeded::None, |accumulator, pd| {
            if matches!(accumulator, UnsafetyNeeded::Always) {
                UnsafetyNeeded::Always
            } else if pd.self_type.is_some() && ignore_receiver {
                if matches!(
                    pd.requires_unsafe,
                    UnsafetyNeeded::Always | UnsafetyNeeded::JustBridge
                ) {
                    UnsafetyNeeded::JustBridge
                } else {
                    accumulator
                }
            } else if matches!(pd.requires_unsafe, UnsafetyNeeded::Always) {
                UnsafetyNeeded::Always
            } else if matches!(accumulator, UnsafetyNeeded::JustBridge)
                || matches!(pd.requires_unsafe, UnsafetyNeeded::JustBridge)
            {
                UnsafetyNeeded::JustBridge
            } else {
                UnsafetyNeeded::None
            }
        })
    }
}

pub(super) fn gen_function(
    ns: &Namespace,
    fun: FuncToConvert,
    analysis: FnAnalysis,
    cpp_call_name: String,
    non_pod_types: &HashSet<QualifiedName>,
) -> RsCodegenResult {
    if analysis.ignore_reason.is_err() || !analysis.externally_callable {
        return RsCodegenResult::default();
    }
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = &analysis.rust_name;
    let ret_type = analysis.ret_type;
    let param_details = analysis.param_details;
    let wrapper_function_needed = analysis.cpp_wrapper.is_some();
    let params = analysis.params;
    let vis = analysis.vis;
    let kind = analysis.kind;
    let doc_attrs = fun.doc_attrs;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let mut trait_impl_entry = None;
    let mut bindgen_mod_items = Vec::new();
    let always_unsafe_due_to_trait_definition = match kind {
        FnKind::TraitMethod { ref details, .. } => details.trait_call_is_unsafe,
        _ => false,
    };
    let fn_generator = FnGenerator {
        param_details: &param_details,
        cxxbridge_name: &cxxbridge_name,
        rust_name,
        unsafety: &analysis.requires_unsafe,
        always_unsafe_due_to_trait_definition,
        doc_attrs: &doc_attrs,
        non_pod_types,
    };
    // In rare occasions, we might need to give an explicit lifetime.
    let (lifetime_tokens, params, ret_type) =
        add_explicit_lifetime_if_necessary(&param_details, params, &ret_type, non_pod_types);

    if analysis.rust_wrapper_needed {
        match kind {
            FnKind::Method {
                ref impl_for,
                method_kind: MethodKind::Constructor { .. },
                ..
            } => {
                // Constructor.
                impl_entry = Some(fn_generator.generate_constructor_impl(impl_for));
            }
            FnKind::Method {
                ref impl_for,
                ref method_kind,
                ..
            } => {
                // Method, or static method.
                impl_entry = Some(fn_generator.generate_method_impl(
                    matches!(
                        method_kind,
                        MethodKind::MakeUnique | MethodKind::Constructor { .. }
                    ),
                    impl_for,
                    &ret_type,
                    if matches!(method_kind, MethodKind::MakeUnique) {
                        Some("Instead, ensure you have imported autocxx::prelude::* (specifically the Within trait) and then use new().within_unique_ptr()")
                    } else {
                        None
                    }
                ));
            }
            FnKind::TraitMethod { ref details, .. } => {
                trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
            }
            _ => {
                // Generate plain old function
                bindgen_mod_items.push(fn_generator.generate_function_impl(&ret_type));
            }
        }
    }

    let materialization = match kind {
        FnKind::Method { .. } | FnKind::TraitMethod { .. } => None,
        FnKind::Function => match analysis.rust_rename_strategy {
            _ if analysis.rust_wrapper_needed => {
                Some(Use::SpecificNameFromBindgen(make_ident(rust_name)))
            }
            RustRenameStrategy::RenameInOutputMod(ref alias) => {
                Some(Use::UsedFromCxxBridgeWithAlias(alias.clone()))
            }
            _ => Some(Use::UsedFromCxxBridge),
        },
    };
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }

    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type.into_owned());
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let bridge_unsafety = analysis.requires_unsafe.bridge_token();
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#cpp_name_attr)*
        #(#doc_attrs)*
        #vis #bridge_unsafety fn #cxxbridge_name #lifetime_tokens ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_items: vec![extern_c_mod_item],
        bindgen_mod_items,
        impl_entry,
        trait_impl_entry,
        materializations: materialization.into_iter().collect(),
        ..Default::default()
    }
}

/// Knows how to generate a given function.
#[derive(Clone)]
struct FnGenerator<'a> {
    param_details: &'a [ArgumentAnalysis],
    cxxbridge_name: &'a Ident,
    rust_name: &'a str,
    unsafety: &'a UnsafetyNeeded,
    always_unsafe_due_to_trait_definition: bool,
    doc_attrs: &'a Vec<Attribute>,
    non_pod_types: &'a HashSet<QualifiedName>,
}

impl<'a> FnGenerator<'a> {
    /// Generate an 'impl Type { methods-go-here }' item
    fn generate_method_impl(
        &self,
        avoid_self: bool,
        impl_block_type_name: &QualifiedName,
        ret_type: &ReturnType,
        deprecation: Option<&str>,
    ) -> Box<ImplBlockDetails> {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(avoid_self, &None, ret_type);
        let rust_name = make_ident(self.rust_name);
        let unsafety = self.unsafety.wrapper_token();
        let doc_attrs = self.doc_attrs;
        let deprecation = deprecation.map(|reason| {
            quote! {
                #[deprecated = #reason]
            }
        });
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #(#doc_attrs)*
                #deprecation
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate an 'impl Trait for Type { methods-go-here }' in its entrety.
    fn generate_trait_impl(
        &self,
        details: &TraitMethodDetails,
        ret_type: &ReturnType,
    ) -> Box<TraitImplBlockDetails> {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(details.avoid_self, &details.parameter_reordering, ret_type);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        let key = details.trt.clone();
        let method_name = &details.method_name;
        let item = parse_quote! {
            #(#doc_attrs)*
            #unsafety fn #method_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                #call_body
            }
        };
        Box::new(TraitImplBlockDetails { item, key })
    }

    /// Generate a 'impl Type { methods-go-here }' item which is a constructor
    /// for use with moveit traits.
    fn generate_constructor_impl(
        &self,
        impl_block_type_name: &QualifiedName,
    ) -> Box<ImplBlockDetails> {
        let ret_type: ReturnType = parse_quote! { -> impl autocxx::moveit::new::New<Output=Self> };
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(true, &None, &ret_type);
        let rust_name = make_ident(&self.rust_name);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #(#doc_attrs)*
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate a function call wrapper
    fn generate_function_impl(&self, ret_type: &ReturnType) -> Item {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(false, &None, &ret_type);
        let rust_name = make_ident(self.rust_name);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        Item::Fn(parse_quote! {
            #(#doc_attrs)*
            pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                #call_body
            }
        })
    }

    fn common_parts<'b>(
        &self,
        avoid_self: bool,
        parameter_reordering: &Option<Vec<usize>>,
        ret_type: &'b ReturnType,
    ) -> (
        Option<TokenStream>,
        Punctuated<FnArg, Comma>,
        std::borrow::Cow<'b, ReturnType>,
        TokenStream,
    ) {
        let mut wrapper_params: Punctuated<FnArg, Comma> = Punctuated::new();
        let mut local_variables = Vec::new();
        let mut arg_list = Vec::new();
        let mut ptr_arg_name = None;
        let wrap_unsafe_calls = self.should_wrap_unsafe_calls();
        for pd in self.param_details {
            let type_name = pd.conversion.rust_wrapper_unconverted_type();
            let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self {
                parse_quote!(self)
            } else {
                pd.name.clone()
            };
            let (local_variable, actual_arg) = pd
                .conversion
                .rust_conversion(wrapper_arg_name.clone(), wrap_unsafe_calls);
            arg_list.push(actual_arg.clone());
            local_variables.extend(local_variable.into_iter());
            if pd.is_placement_return_destination {
                ptr_arg_name = Some(actual_arg);
            } else {
                let param_mutability = pd.conversion.rust_conversion.requires_mutability();
                wrapper_params.push(parse_quote!(
                    #param_mutability #wrapper_arg_name: #type_name
                ));
            }
        }
        let local_variables = quote! { #(#local_variables);* };
        if let Some(parameter_reordering) = &parameter_reordering {
            wrapper_params = Self::reorder_parameters(wrapper_params, parameter_reordering);
        }
        let (lifetime_tokens, wrapper_params, ret_type) = add_explicit_lifetime_if_necessary(
            self.param_details,
            wrapper_params,
            ret_type,
            self.non_pod_types,
        );

        let cxxbridge_name = self.cxxbridge_name;
        let call_body = quote! {
            cxxbridge::#cxxbridge_name ( #(#arg_list),* )
        };
        let call_body = if let Some(ptr_arg_name) = ptr_arg_name {
            quote! {
                #local_variables
                autocxx::moveit::new::by_raw(move |#ptr_arg_name| {
                    let #ptr_arg_name = #ptr_arg_name.get_unchecked_mut().as_mut_ptr();
                    #call_body
                })
            }
        } else {
            call_body
        };
        let call_body = if self.should_wrap_unsafe_calls() {
            quote! {
                unsafe {
                    #call_body
                }
            }
        } else {
            call_body
        };
        (lifetime_tokens, wrapper_params, ret_type, call_body)
    }

    fn should_wrap_unsafe_calls(&self) -> bool {
        matches!(self.unsafety, UnsafetyNeeded::JustBridge)
            || self.always_unsafe_due_to_trait_definition
    }

    fn reorder_parameters(
        params: Punctuated<FnArg, Comma>,
        parameter_ordering: &[usize],
    ) -> Punctuated<FnArg, Comma> {
        let old_params = params.into_iter().collect::<Vec<_>>();
        parameter_ordering
            .iter()
            .map(|n| old_params.get(*n).unwrap().clone())
            .collect()
    }
}
<commit_msg>Clippy fix.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashSet;

use proc_macro2::TokenStream;
use quote::quote;
use syn::{
    parse::Parser,
    parse_quote,
    punctuated::Punctuated,
    token::{Comma, Unsafe},
    Attribute, FnArg, ForeignItem, Ident, ImplItem, Item, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    ImplBlockDetails, RsCodegenResult, TraitImplBlockDetails, Use,
};
use crate::{
    conversion::{
        analysis::fun::{
            ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
            TraitMethodDetails,
        },
        api::UnsafetyNeeded,
    },
    types::{Namespace, QualifiedName},
};
use crate::{
    conversion::{api::FuncToConvert, codegen_rs::lifetime::add_explicit_lifetime_if_necessary},
    types::make_ident,
};

impl UnsafetyNeeded {
    pub(crate) fn bridge_token(&self) -> Option<Unsafe> {
        match self {
            UnsafetyNeeded::None => None,
            _ => Some(parse_quote! { unsafe }),
        }
    }

    pub(crate) fn wrapper_token(&self) -> Option<Unsafe> {
        match self {
            UnsafetyNeeded::Always => Some(parse_quote! { unsafe }),
            _ => None,
        }
    }

    pub(crate) fn from_param_details(params: &[ArgumentAnalysis], ignore_receiver: bool) -> Self {
        params.iter().fold(UnsafetyNeeded::None, |accumulator, pd| {
            if matches!(accumulator, UnsafetyNeeded::Always) {
                UnsafetyNeeded::Always
            } else if pd.self_type.is_some() && ignore_receiver {
                if matches!(
                    pd.requires_unsafe,
                    UnsafetyNeeded::Always | UnsafetyNeeded::JustBridge
                ) {
                    UnsafetyNeeded::JustBridge
                } else {
                    accumulator
                }
            } else if matches!(pd.requires_unsafe, UnsafetyNeeded::Always) {
                UnsafetyNeeded::Always
            } else if matches!(accumulator, UnsafetyNeeded::JustBridge)
                || matches!(pd.requires_unsafe, UnsafetyNeeded::JustBridge)
            {
                UnsafetyNeeded::JustBridge
            } else {
                UnsafetyNeeded::None
            }
        })
    }
}

pub(super) fn gen_function(
    ns: &Namespace,
    fun: FuncToConvert,
    analysis: FnAnalysis,
    cpp_call_name: String,
    non_pod_types: &HashSet<QualifiedName>,
) -> RsCodegenResult {
    if analysis.ignore_reason.is_err() || !analysis.externally_callable {
        return RsCodegenResult::default();
    }
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = &analysis.rust_name;
    let ret_type = analysis.ret_type;
    let param_details = analysis.param_details;
    let wrapper_function_needed = analysis.cpp_wrapper.is_some();
    let params = analysis.params;
    let vis = analysis.vis;
    let kind = analysis.kind;
    let doc_attrs = fun.doc_attrs;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let mut trait_impl_entry = None;
    let mut bindgen_mod_items = Vec::new();
    let always_unsafe_due_to_trait_definition = match kind {
        FnKind::TraitMethod { ref details, .. } => details.trait_call_is_unsafe,
        _ => false,
    };
    let fn_generator = FnGenerator {
        param_details: &param_details,
        cxxbridge_name: &cxxbridge_name,
        rust_name,
        unsafety: &analysis.requires_unsafe,
        always_unsafe_due_to_trait_definition,
        doc_attrs: &doc_attrs,
        non_pod_types,
    };
    // In rare occasions, we might need to give an explicit lifetime.
    let (lifetime_tokens, params, ret_type) =
        add_explicit_lifetime_if_necessary(&param_details, params, &ret_type, non_pod_types);

    if analysis.rust_wrapper_needed {
        match kind {
            FnKind::Method {
                ref impl_for,
                method_kind: MethodKind::Constructor { .. },
                ..
            } => {
                // Constructor.
                impl_entry = Some(fn_generator.generate_constructor_impl(impl_for));
            }
            FnKind::Method {
                ref impl_for,
                ref method_kind,
                ..
            } => {
                // Method, or static method.
                impl_entry = Some(fn_generator.generate_method_impl(
                    matches!(
                        method_kind,
                        MethodKind::MakeUnique | MethodKind::Constructor { .. }
                    ),
                    impl_for,
                    &ret_type,
                    if matches!(method_kind, MethodKind::MakeUnique) {
                        Some("Instead, ensure you have imported autocxx::prelude::* (specifically the Within trait) and then use new().within_unique_ptr()")
                    } else {
                        None
                    }
                ));
            }
            FnKind::TraitMethod { ref details, .. } => {
                trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
            }
            _ => {
                // Generate plain old function
                bindgen_mod_items.push(fn_generator.generate_function_impl(&ret_type));
            }
        }
    }

    let materialization = match kind {
        FnKind::Method { .. } | FnKind::TraitMethod { .. } => None,
        FnKind::Function => match analysis.rust_rename_strategy {
            _ if analysis.rust_wrapper_needed => {
                Some(Use::SpecificNameFromBindgen(make_ident(rust_name)))
            }
            RustRenameStrategy::RenameInOutputMod(ref alias) => {
                Some(Use::UsedFromCxxBridgeWithAlias(alias.clone()))
            }
            _ => Some(Use::UsedFromCxxBridge),
        },
    };
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }

    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type.into_owned());
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let bridge_unsafety = analysis.requires_unsafe.bridge_token();
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#cpp_name_attr)*
        #(#doc_attrs)*
        #vis #bridge_unsafety fn #cxxbridge_name #lifetime_tokens ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_items: vec![extern_c_mod_item],
        bindgen_mod_items,
        impl_entry,
        trait_impl_entry,
        materializations: materialization.into_iter().collect(),
        ..Default::default()
    }
}

/// Knows how to generate a given function.
#[derive(Clone)]
struct FnGenerator<'a> {
    param_details: &'a [ArgumentAnalysis],
    cxxbridge_name: &'a Ident,
    rust_name: &'a str,
    unsafety: &'a UnsafetyNeeded,
    always_unsafe_due_to_trait_definition: bool,
    doc_attrs: &'a Vec<Attribute>,
    non_pod_types: &'a HashSet<QualifiedName>,
}

impl<'a> FnGenerator<'a> {
    /// Generate an 'impl Type { methods-go-here }' item
    fn generate_method_impl(
        &self,
        avoid_self: bool,
        impl_block_type_name: &QualifiedName,
        ret_type: &ReturnType,
        deprecation: Option<&str>,
    ) -> Box<ImplBlockDetails> {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(avoid_self, &None, ret_type);
        let rust_name = make_ident(self.rust_name);
        let unsafety = self.unsafety.wrapper_token();
        let doc_attrs = self.doc_attrs;
        let deprecation = deprecation.map(|reason| {
            quote! {
                #[deprecated = #reason]
            }
        });
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #(#doc_attrs)*
                #deprecation
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate an 'impl Trait for Type { methods-go-here }' in its entrety.
    fn generate_trait_impl(
        &self,
        details: &TraitMethodDetails,
        ret_type: &ReturnType,
    ) -> Box<TraitImplBlockDetails> {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(details.avoid_self, &details.parameter_reordering, ret_type);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        let key = details.trt.clone();
        let method_name = &details.method_name;
        let item = parse_quote! {
            #(#doc_attrs)*
            #unsafety fn #method_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                #call_body
            }
        };
        Box::new(TraitImplBlockDetails { item, key })
    }

    /// Generate a 'impl Type { methods-go-here }' item which is a constructor
    /// for use with moveit traits.
    fn generate_constructor_impl(
        &self,
        impl_block_type_name: &QualifiedName,
    ) -> Box<ImplBlockDetails> {
        let ret_type: ReturnType = parse_quote! { -> impl autocxx::moveit::new::New<Output=Self> };
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(true, &None, &ret_type);
        let rust_name = make_ident(&self.rust_name);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #(#doc_attrs)*
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate a function call wrapper
    fn generate_function_impl(&self, ret_type: &ReturnType) -> Item {
        let (lifetime_tokens, wrapper_params, ret_type, call_body) =
            self.common_parts(false, &None, ret_type);
        let rust_name = make_ident(self.rust_name);
        let doc_attrs = self.doc_attrs;
        let unsafety = self.unsafety.wrapper_token();
        Item::Fn(parse_quote! {
            #(#doc_attrs)*
            pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                #call_body
            }
        })
    }

    fn common_parts<'b>(
        &self,
        avoid_self: bool,
        parameter_reordering: &Option<Vec<usize>>,
        ret_type: &'b ReturnType,
    ) -> (
        Option<TokenStream>,
        Punctuated<FnArg, Comma>,
        std::borrow::Cow<'b, ReturnType>,
        TokenStream,
    ) {
        let mut wrapper_params: Punctuated<FnArg, Comma> = Punctuated::new();
        let mut local_variables = Vec::new();
        let mut arg_list = Vec::new();
        let mut ptr_arg_name = None;
        let wrap_unsafe_calls = self.should_wrap_unsafe_calls();
        for pd in self.param_details {
            let type_name = pd.conversion.rust_wrapper_unconverted_type();
            let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self {
                parse_quote!(self)
            } else {
                pd.name.clone()
            };
            let (local_variable, actual_arg) = pd
                .conversion
                .rust_conversion(wrapper_arg_name.clone(), wrap_unsafe_calls);
            arg_list.push(actual_arg.clone());
            local_variables.extend(local_variable.into_iter());
            if pd.is_placement_return_destination {
                ptr_arg_name = Some(actual_arg);
            } else {
                let param_mutability = pd.conversion.rust_conversion.requires_mutability();
                wrapper_params.push(parse_quote!(
                    #param_mutability #wrapper_arg_name: #type_name
                ));
            }
        }
        let local_variables = quote! { #(#local_variables);* };
        if let Some(parameter_reordering) = &parameter_reordering {
            wrapper_params = Self::reorder_parameters(wrapper_params, parameter_reordering);
        }
        let (lifetime_tokens, wrapper_params, ret_type) = add_explicit_lifetime_if_necessary(
            self.param_details,
            wrapper_params,
            ret_type,
            self.non_pod_types,
        );

        let cxxbridge_name = self.cxxbridge_name;
        let call_body = quote! {
            cxxbridge::#cxxbridge_name ( #(#arg_list),* )
        };
        let call_body = if let Some(ptr_arg_name) = ptr_arg_name {
            quote! {
                #local_variables
                autocxx::moveit::new::by_raw(move |#ptr_arg_name| {
                    let #ptr_arg_name = #ptr_arg_name.get_unchecked_mut().as_mut_ptr();
                    #call_body
                })
            }
        } else {
            call_body
        };
        let call_body = if self.should_wrap_unsafe_calls() {
            quote! {
                unsafe {
                    #call_body
                }
            }
        } else {
            call_body
        };
        (lifetime_tokens, wrapper_params, ret_type, call_body)
    }

    fn should_wrap_unsafe_calls(&self) -> bool {
        matches!(self.unsafety, UnsafetyNeeded::JustBridge)
            || self.always_unsafe_due_to_trait_definition
    }

    fn reorder_parameters(
        params: Punctuated<FnArg, Comma>,
        parameter_ordering: &[usize],
    ) -> Punctuated<FnArg, Comma> {
        let old_params = params.into_iter().collect::<Vec<_>>();
        parameter_ordering
            .iter()
            .map(|n| old_params.get(*n).unwrap().clone())
            .collect()
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use uuid::Uuid;
use chrono::{NaiveDateTime, Utc};
use postgres;
use error::Error;
use super::{conn, Model};
use model::track::{Track, PROPS as TRACK_PROPS};
use model::playlist::Playlist;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PlaylistTrack {
    pub playlist_id:   Uuid,
    pub track_id:      Uuid,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub track:         Track,
}

static PROPS: [&'static str; 4]  = ["playlist_id",
                                    "track_id",
                                    "created_at",
                                    "updated_at"];

impl PlaylistTrack {
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn row_to_item(row: postgres::rows::Row) -> Self {
        let offset = TRACK_PROPS.len();
        PlaylistTrack {
            playlist_id: row.get(offset),
            track_id:    row.get(offset + 1),
            created_at:  row.get(offset + 2),
            updated_at:  row.get(offset + 3),
            track:       Track::row_to_item(row),
        }
    }
    pub fn find_by_playlist_ids(playlist_ids: Vec<Uuid>) -> Result<BTreeMap<Uuid, Vec<PlaylistTrack>>, Error> {
        let conn = conn().unwrap();
        let sql = format!("SELECT {}, {} FROM tracks
                      LEFT OUTER JOIN playlist_tracks
                      ON playlist_tracks.track_id = tracks.id
                      WHERE playlist_tracks.playlist_id = ANY($1)
                      ORDER BY playlist_tracks.updated_at DESC",
                          Track::props_str("tracks."),
                          PlaylistTrack::props_str("playlist_tracks."));
        let stmt = conn.prepare(&sql).map_err(|e| {
            println!("{:?}", e);
            e
        })?;
        let rows = stmt.query(&[&playlist_ids]).map_err(|e| {
            println!("{:?}", e);
            e
        })?;
        let mut items: BTreeMap<Uuid, Vec<PlaylistTrack>> = BTreeMap::new();
        for id in playlist_ids.iter() {
            items.insert(*id, vec![]);
        }
        for row in rows.iter() {
            let id: Uuid = row.get(TRACK_PROPS.len());
            if let Some(playlist_tracks) = items.get_mut(&id) {
                let pt = PlaylistTrack::row_to_item(row);
                playlist_tracks.push(pt);
            }
        };
        Ok(items)
    }
    pub fn upsert(playlist: &Playlist, track: &Track) -> Result<PlaylistTrack, Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlist_tracks
                      (track_id, playlist_id, created_at, updated_at)
                      VALUES ($1, $2, $3, $4)
                      ON CONFLICT (track_id, playlist_id)
                      DO UPDATE SET updated_at=$4
                      RETURNING playlist_tracks.created_at, playlist_tracks.updated_at")?;
        let now = Utc::now().naive_utc();
        let rows = stmt.query(&[&track.id, &playlist.id, &now, &now])?;
        let row = rows.iter().next().ok_or(Error::Unexpected)?;
        Ok(PlaylistTrack {
            playlist_id: playlist.id,
            track_id:    track.id,
            created_at:  row.get(0),
            updated_at:  row.get(1),
            track:       track.clone(),
        })
    }
}
<commit_msg>Sort playlist tracks created_at DESC<commit_after>use std::collections::BTreeMap;
use uuid::Uuid;
use chrono::{NaiveDateTime, Utc};
use postgres;
use error::Error;
use super::{conn, Model};
use model::track::{Track, PROPS as TRACK_PROPS};
use model::playlist::Playlist;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PlaylistTrack {
    pub playlist_id:   Uuid,
    pub track_id:      Uuid,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub track:         Track,
}

static PROPS: [&'static str; 4]  = ["playlist_id",
                                    "track_id",
                                    "created_at",
                                    "updated_at"];

impl PlaylistTrack {
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn row_to_item(row: postgres::rows::Row) -> Self {
        let offset = TRACK_PROPS.len();
        PlaylistTrack {
            playlist_id: row.get(offset),
            track_id:    row.get(offset + 1),
            created_at:  row.get(offset + 2),
            updated_at:  row.get(offset + 3),
            track:       Track::row_to_item(row),
        }
    }
    pub fn find_by_playlist_ids(playlist_ids: Vec<Uuid>) -> Result<BTreeMap<Uuid, Vec<PlaylistTrack>>, Error> {
        let conn = conn().unwrap();
        let sql = format!("SELECT {}, {} FROM tracks
                      LEFT OUTER JOIN playlist_tracks
                      ON playlist_tracks.track_id = tracks.id
                      WHERE playlist_tracks.playlist_id = ANY($1)
                      ORDER BY playlist_tracks.created_at DESC",
                          Track::props_str("tracks."),
                          PlaylistTrack::props_str("playlist_tracks."));
        let stmt = conn.prepare(&sql).map_err(|e| {
            println!("{:?}", e);
            e
        })?;
        let rows = stmt.query(&[&playlist_ids]).map_err(|e| {
            println!("{:?}", e);
            e
        })?;
        let mut items: BTreeMap<Uuid, Vec<PlaylistTrack>> = BTreeMap::new();
        for id in playlist_ids.iter() {
            items.insert(*id, vec![]);
        }
        for row in rows.iter() {
            let id: Uuid = row.get(TRACK_PROPS.len());
            if let Some(playlist_tracks) = items.get_mut(&id) {
                let pt = PlaylistTrack::row_to_item(row);
                playlist_tracks.push(pt);
            }
        };
        Ok(items)
    }
    pub fn upsert(playlist: &Playlist, track: &Track) -> Result<PlaylistTrack, Error> {
        let conn = conn()?;
        let stmt = conn.prepare("INSERT INTO playlist_tracks
                      (track_id, playlist_id, created_at, updated_at)
                      VALUES ($1, $2, $3, $4)
                      ON CONFLICT (track_id, playlist_id)
                      DO UPDATE SET updated_at=$4
                      RETURNING playlist_tracks.created_at, playlist_tracks.updated_at")?;
        let now = Utc::now().naive_utc();
        let rows = stmt.query(&[&track.id, &playlist.id, &now, &now])?;
        let row = rows.iter().next().ok_or(Error::Unexpected)?;
        Ok(PlaylistTrack {
            playlist_id: playlist.id,
            track_id:    track.id,
            created_at:  row.get(0),
            updated_at:  row.get(1),
            track:       track.clone(),
        })
    }
}
<|endoftext|>


<commit_before>use test::Bencher;

use super::Cache;
use super::Key;
use super::Value;

#[bench]
fn bench_set_get_key(b: &mut Bencher) {
    let mut cache = Cache::new(1024);

    b.iter(|| {
        // Set a key
        cache.set(key!(1), value!(9));
        cache.get(&key!(1));
    })
}
<commit_msg>remove pointless comment<commit_after>use test::Bencher;

use super::Cache;
use super::Key;
use super::Value;

#[bench]
fn bench_set_get_key(b: &mut Bencher) {
    let mut cache = Cache::new(1024);

    b.iter(|| {
        cache.set(key!(1), value!(9));
        cache.get(&key!(1));
    })
}
<|endoftext|>


<commit_before>//! Check RAM usage of the currently-running container

extern crate rustc_serialize;
extern crate docopt;

extern crate turbine_plugins;

use std::cmp::max;

use docopt::Docopt;

use turbine_plugins::Status;
use turbine_plugins::sys::fs::cgroup::memory::{Stat, limit_in_bytes};
use turbine_plugins::linux::{pages_to_human_size, bytes_to_human_size};
use turbine_plugins::procfs::{RunningProcs, MemInfo};

static USAGE: &'static str = "
Usage:
    check-container-ram [--show-hogs=<count>] [--invalid-limit=<status>] [options]
    check-container-ram (-h | --help)

Check the RAM usage of the currently-running container. This must be run from
inside the container to be checked.

This checks as a ratio of the limit specified in the cgroup memory limit, and
if there is no limit set (or the limit is greater than the total memory
available on the system) this checks against the total system memory.

Options:
    -h, --help                 Show this message and exit

    -w, --warn=<percent>       Warn at this percent used           [default: 85]
    -c, --crit=<percent>       Critical at this percent used       [default: 95]

    --invalid-limit=<status>   Status to consider this check if the CGroup limit
                               is greater than the system ram      [default: ok]

    --show-hogs=<count>        Show the most ram-hungry procs      [default: 0]
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_warn: f64,
    flag_crit: f64,

    flag_invalid_limit: Status,
    flag_show_hogs: u32
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    let mut status = Status::Ok;

    let mut limit = limit_in_bytes().unwrap();
    let mem = MemInfo::load();
    let system_bytes = mem.total.unwrap() * 1024;
    if limit > system_bytes {
        if args.flag_invalid_limit != Status::Ok {
            println!("{}: CGroup memory limit is greater than system memory ({} > {})",
                     args.flag_invalid_limit,
                     bytes_to_human_size(limit as u64),
                     bytes_to_human_size(system_bytes as u64));
            status = args.flag_invalid_limit;
        }
        limit = system_bytes;
    }

    let cgroup_stat = Stat::load().unwrap();
    let ratio = cgroup_stat.rss as f64 / limit as f64;
    let percent = ratio * 100.0;

    if percent > args.flag_crit {
        println!("CRITICAL: cgroup is using {:.1}% of {} limit (greater than {}%)",
                 percent, bytes_to_human_size(limit as u64), args.flag_crit);
        status = Status::Critical;
    } else if percent > args.flag_warn {
        println!("WARNING: cgroup is using {:.1}% of {} limit (greater than {}%)",
                 percent, bytes_to_human_size(limit as u64), args.flag_warn);
        status = max(status, Status::Warning);
    } else {
        println!("OK: cgroup is using {:.1}% of {} limit (less than {}%)",
                 percent, bytes_to_human_size(limit as u64), args.flag_warn);
    }

    if args.flag_show_hogs > 0 {
        let per_proc = RunningProcs::currently_running().unwrap();
        let mut procs = per_proc.0.values().collect::<Vec<_>>();
        procs.sort_by(|l, r| r.stat.rss.cmp(&l.stat.rss));
        println!("INFO [check-container-ram]: ram hogs");
        for process in procs.iter().take(args.flag_show_hogs as usize) {
            let percent = process.percent_ram(limit);
            println!("[{:>6}]{:>5.1}% {}: {}",
                     process.stat.pid,
                     percent, pages_to_human_size(process.stat.rss),
                     process.useful_cmdline());
        }
    }
    status.exit();
}

#[cfg(test)]
mod unit {

    use docopt::Docopt;
    use turbine_plugins::Status;
    use super::{USAGE, Args};

    #[test]
    fn usage_is_valid() {
        let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap();
        assert_eq!(args.flag_crit, 95.0);
        assert_eq!(args.flag_invalid_limit, Status::Ok);
        let args: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(vec!["arg0", "--crit", "80", "--warn", "20"].into_iter())
                      .decode())
            .unwrap();
        assert_eq!(args.flag_crit, 80.0);

    }
}
<commit_msg>check-c-ram: Show the limit type in output<commit_after>//! Check RAM usage of the currently-running container

extern crate rustc_serialize;
extern crate docopt;

extern crate turbine_plugins;

use std::fmt;
use std::cmp::max;

use docopt::Docopt;

use turbine_plugins::Status;
use turbine_plugins::sys::fs::cgroup::memory::{Stat, limit_in_bytes};
use turbine_plugins::linux::{pages_to_human_size, bytes_to_human_size};
use turbine_plugins::procfs::{RunningProcs, MemInfo};

static USAGE: &'static str = "
Usage:
    check-container-ram [--show-hogs=<count>] [--invalid-limit=<status>] [options]
    check-container-ram (-h | --help)

Check the RAM usage of the currently-running container. This must be run from
inside the container to be checked.

This checks as a ratio of the limit specified in the cgroup memory limit, and
if there is no limit set (or the limit is greater than the total memory
available on the system) this checks against the total system memory.

Options:
    -h, --help                 Show this message and exit

    -w, --warn=<percent>       Warn at this percent used           [default: 85]
    -c, --crit=<percent>       Critical at this percent used       [default: 95]

    --invalid-limit=<status>   Status to consider this check if the CGroup limit
                               is greater than the system ram      [default: ok]

    --show-hogs=<count>        Show the most ram-hungry procs      [default: 0]
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_warn: f64,
    flag_crit: f64,

    flag_invalid_limit: Status,
    flag_show_hogs: u32
}

enum Limit {
    CGroup,
    System
}

impl fmt::Display for Limit {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Limit::CGroup => write!(f, "cgroup limit"),
            Limit::System => write!(f, "system ram")
        }
    }
}

fn main() {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    let mut status = Status::Ok;

    let mut limit = limit_in_bytes().unwrap();
    let mut limit_type = Limit::CGroup;
    let mem = MemInfo::load();
    let system_bytes = mem.total.unwrap() * 1024;
    if limit > system_bytes {
        if args.flag_invalid_limit != Status::Ok {
            println!("{}: CGroup memory limit is greater than system memory ({} > {})",
                     args.flag_invalid_limit,
                     bytes_to_human_size(limit as u64),
                     bytes_to_human_size(system_bytes as u64));
            status = args.flag_invalid_limit;
        }
        limit = system_bytes;
        limit_type = Limit::System;
    }

    let cgroup_stat = Stat::load().unwrap();
    let ratio = cgroup_stat.rss as f64 / limit as f64;
    let percent = ratio * 100.0;

    if percent > args.flag_crit {
        println!("CRITICAL: cgroup is using {:.1}% of {} {} (greater than {}%)",
                 percent, bytes_to_human_size(limit as u64), limit_type, args.flag_crit);
        status = Status::Critical;
    } else if percent > args.flag_warn {
        println!("WARNING: cgroup is using {:.1}% of {} {} (greater than {}%)",
                 percent, bytes_to_human_size(limit as u64), limit_type, args.flag_warn);
        status = max(status, Status::Warning);
    } else {
        println!("OK: cgroup is using {:.1}% of {} {} (less than {}%)",
                 percent, bytes_to_human_size(limit as u64), limit_type, args.flag_warn);
    }

    if args.flag_show_hogs > 0 {
        let per_proc = RunningProcs::currently_running().unwrap();
        let mut procs = per_proc.0.values().collect::<Vec<_>>();
        procs.sort_by(|l, r| r.stat.rss.cmp(&l.stat.rss));
        println!("INFO [check-container-ram]: ram hogs");
        for process in procs.iter().take(args.flag_show_hogs as usize) {
            let percent = process.percent_ram(limit);
            println!("[{:>6}]{:>5.1}% {}: {}",
                     process.stat.pid,
                     percent, pages_to_human_size(process.stat.rss),
                     process.useful_cmdline());
        }
    }
    status.exit();
}

#[cfg(test)]
mod unit {

    use docopt::Docopt;
    use turbine_plugins::Status;
    use super::{USAGE, Args};

    #[test]
    fn usage_is_valid() {
        let args: Args = Docopt::new(USAGE).and_then(|d| d.decode()).unwrap();
        assert_eq!(args.flag_crit, 95.0);
        assert_eq!(args.flag_invalid_limit, Status::Ok);
        let args: Args = Docopt::new(USAGE)
            .and_then(|d| d.argv(vec!["arg0", "--crit", "80", "--warn", "20"].into_iter())
                      .decode())
            .unwrap();
        assert_eq!(args.flag_crit, 80.0);

    }
}
<|endoftext|>


<commit_before>/**
 * http://doc.rust-lang.org/std/vec/
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

/**
 * ~[~str] is an owned pointer, allocated on the send heap, can be sent accross tasks.
 * Does not handle .push() since 0.11-pre, so I use Vec<~str>
 */
fn fill_strings() -> ~[String] {
	let mut strings = vec!("hello".to_string());
	strings.push("world".to_string());
	strings.as_slice().to_owned()
}

/**
 * Use of Vec::from_elem to create a dynamic two dimensional array.
 */
fn make_2d_array(dim1: uint, dim2: uint, default: int) -> ~[~[int]] {
	Vec::from_elem(dim1, Vec::from_elem(dim2, default).as_slice().to_owned()).as_slice().to_owned()
}

fn main() {
	/*
	 * Simple use
	 * .iter() returns an iteration value for a vector or a vector slice.
	 *  The iterator yields borrowed pointers to the vector's elements,
	 *  so if the element type of the vector is int, the element type of the iterator is &int.
	 */
	let numbers = [0, 1, 2];
	for &x in numbers.iter() {
		println!("element in numbers: {}", x);
	}

	/*
	 * .slice(a, b) returns an immutable "view" into a vector or a vector slice from the interval (a, b)
	 * .push() adds an item at the end of an OwnedVector
	 */
	let mut numbers2 = Vec::new();
	for &x in numbers.slice(1, 3).iter() {
		numbers2.push(x);
	}
	for &x in numbers2.iter() {
		println!("element in numbers2: {}", x);
	}

	/*
	 * Create a vector in a function.
	 */
	let mut strings = fill_strings();
	println!("strings[1] = {}", strings[1]);
	strings[1] = "me".to_string();
	println!("strings[1] = {}", strings[1]);

	/*
	 * Create a two dimensional vector.
	 */
	let mut array2d = [[0u8, ..4], ..4];
	println!("array2d[0][0] = {}", array2d[0][0]);
	array2d[0][1] = 1;
	println!("array2d[0][1] = {}", array2d[0][1]);

	/*
	 * Create a two dimensional dynamic vector.
	 */
	let mut anotherArray2d = make_2d_array(2, 3, -1);
	println!("anotherArray2d[0][0] = {}", anotherArray2d[0][0]);
	anotherArray2d[0][1] = 1;
	println!("anotherArray2d[0][1] = {}", anotherArray2d[0][1]);
}

<commit_msg>Changes to version 0.11-pre (dbd29ea 2014-06-14 08:46:48 +0000)<commit_after>/**
 * http://doc.rust-lang.org/std/vec/
 *
 * @license MIT license <http://www.opensource.org/licenses/mit-license.php>
 */

/**
 * ~[~str] is an owned pointer, allocated on the send heap, can be sent accross tasks.
 * Vec<T> is what ~[T] was before it was removed.
 */
fn fill_strings() -> Vec<String> {
	let mut strings = vec!("hello".to_string());
	strings.push("world".to_string());
	strings
}

/**
 * Use of Vec::from_elem to create a dynamic two dimensional array.
 */
fn make_2d_array(dim1: uint, dim2: uint, default: int) -> Vec<Vec<int>> {
	Vec::from_elem(dim1, Vec::from_elem(dim2, default))
}

fn main() {
	/*
	 * Simple use
	 * .iter() returns an iteration value for a vector or a vector slice.
	 *  The iterator yields borrowed pointers to the vector's elements,
	 *  so if the element type of the vector is int, the element type of the iterator is &int.
	 */
	let numbers = [0, 1, 2];
	for &x in numbers.iter() {
		println!("element in numbers: {}", x);
	}

	/*
	 * .slice(a, b) returns an immutable "view" into a vector or a vector slice from the interval (a, b)
	 * .push() adds an item at the end of an OwnedVector
	 */
	let mut numbers2 = Vec::new();
	for &x in numbers.slice(1, 3).iter() {
		numbers2.push(x);
	}
	for &x in numbers2.iter() {
		println!("element in numbers2: {}", x);
	}

	/*
	 * Create a vector in a function.
	 */
	let mut ret = fill_strings();
	let strings = ret.as_mut_slice();
	println!("strings[1] = {}", strings[1]);
	strings[1] = "me".to_string();
	println!("strings[1] = {}", strings[1]);

	/*
	 * Create a two dimensional vector.
	 */
	let mut array2d = [[0u8, ..4], ..4];
	println!("array2d[0][0] = {}", array2d[0][0]);
	array2d[0][1] = 1;
	println!("array2d[0][1] = {}", array2d[0][1]);

	/*
	 * Create a two dimensional dynamic vector.
	 */
	let mut anotherArray2d = make_2d_array(2, 3, -1);
	println!("anotherArray2d[0][0] = {}", anotherArray2d.get(0).get(0));
	*(anotherArray2d.get_mut(0).get_mut(1)) = 1;
	println!("anotherArray2d[0][1] = {}", anotherArray2d.get(0).get(1));
}

<|endoftext|>


<commit_before>#![deny(warnings)]
#![warn(rust_2018_idioms)]

#[macro_use]
extern crate serde_derive;

use bytes::Buf as _;
use hyper::Client;
use hyper_tls::HttpsConnector;

// A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[tokio::main]
async fn main() -> Result<()> {
    let url = "https://jsonplaceholder.typicode.com/users".parse().unwrap();
    let users = fetch_json(url).await?;
    // print users
    println!("users: {:#?}", users);

    // print the sum of ids
    let sum = users.iter().fold(0, |acc, user| acc + user.id);
    println!("sum of ids: {}", sum);
    Ok(())
}

async fn fetch_json(url: hyper::Uri) -> Result<Vec<User>> {
    let https = HttpsConnector::new();

    //let client = Client::new();
    let client = Client::builder().build::<_, hyper::Body>(https);

    // Fetch the url...
    let res = client.get(url).await?;

    // asynchronously aggregate the chunks of the body
    let body = hyper::body::aggregate(res).await?;

    // try to parse as json with serde_json
    let users = serde_json::from_reader(body.reader())?;

    Ok(users)
}

#[derive(Deserialize, Debug)]
struct User {
    id: i32,
    name: String,
}
<commit_msg>adding a comment to make things better<commit_after>#![deny(warnings)]
#![warn(rust_2018_idioms)]

#[macro_use]
extern crate serde_derive;

use bytes::Buf as _;
use hyper::Client;
// if you are using this remember to add the configs in .cargo/config
use hyper_tls::HttpsConnector;

// A simple type alias so as to DRY.
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;

#[tokio::main]
async fn main() -> Result<()> {
    let url = "https://jsonplaceholder.typicode.com/users".parse().unwrap();
    let users = fetch_json(url).await?;
    // print users
    println!("users: {:#?}", users);

    // print the sum of ids
    let sum = users.iter().fold(0, |acc, user| acc + user.id);
    println!("sum of ids: {}", sum);
    Ok(())
}

async fn fetch_json(url: hyper::Uri) -> Result<Vec<User>> {
    let https = HttpsConnector::new();

    //let client = Client::new();
    let client = Client::builder().build::<_, hyper::Body>(https);

    // Fetch the url...
    let res = client.get(url).await?;

    // asynchronously aggregate the chunks of the body
    let body = hyper::body::aggregate(res).await?;

    // try to parse as json with serde_json
    let users = serde_json::from_reader(body.reader())?;

    Ok(users)
}

#[derive(Deserialize, Debug)]
struct User {
    id: i32,
    name: String,
}
<|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::sync::Arc;
use std::sync::Mutex;

use OomError;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::DescriptorPoolAlloc;
use descriptor::descriptor_set::DescriptorPoolAllocError;
use descriptor::descriptor_set::DescriptorsCount;
use descriptor::descriptor_set::UnsafeDescriptorPool;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use device::Device;
use device::DeviceOwned;

/// Standard implementation of a descriptor pool.
///
/// Whenever a set is allocated, this implementation will try to find a pool that has some space
/// for it. If there is one, allocate from it. If there is none, create a new pool whose capacity
/// is 40 sets and 40 times the requested descriptors. This number is arbitrary.
pub struct StdDescriptorPool {
    device: Arc<Device>,
    pools: Mutex<Vec<Arc<Mutex<Pool>>>>,
}

struct Pool {
    pool: UnsafeDescriptorPool,
    remaining_capacity: DescriptorsCount,
    remaining_sets_count: u32,
}

impl StdDescriptorPool {
    /// Builds a new `StdDescriptorPool`.
    pub fn new(device: Arc<Device>) -> StdDescriptorPool {
        StdDescriptorPool {
            device: device,
            pools: Mutex::new(Vec::new()),
        }
    }
}

/// A descriptor set allocated from a `StdDescriptorPool`.
pub struct StdDescriptorPoolAlloc {
    pool: Arc<Mutex<Pool>>,
    // The set. Inside an option so that we can extract it in the destructor.
    set: Option<UnsafeDescriptorSet>,
    // We need to keep track of this count in order to add it back to the capacity when freeing.
    descriptors: DescriptorsCount,
}

unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
    type Alloc = StdDescriptorPoolAlloc;

    // TODO: eventually use a lock-free algorithm?
    fn alloc(&mut self, layout: &UnsafeDescriptorSetLayout)
             -> Result<StdDescriptorPoolAlloc, OomError> {
        let mut pools = self.pools.lock().unwrap();

        // Try find an existing pool with some free space.
        for pool_arc in pools.iter_mut() {
            let mut pool = pool_arc.lock().unwrap();

            if pool.remaining_sets_count == 0 {
                continue;
            }

            if !(pool.remaining_capacity >= *layout.descriptors_count()) {
                continue;
            }

            // Note that we decrease these values *before* trying to allocate from the pool.
            // If allocating from the pool results in an error, we just ignore it. In order to
            // avoid trying the same failing pool every time, we "pollute" it by reducing the
            // available space.
            pool.remaining_sets_count -= 1;
            pool.remaining_capacity -= *layout.descriptors_count();

            let alloc = unsafe {
                match pool.pool.alloc(Some(layout)) {
                    Ok(mut sets) => sets.next().unwrap(),
                    // An error can happen if we're out of memory, or if the pool is fragmented.
                    // We handle these errors by just ignoring this pool and trying the next ones.
                    Err(_) => continue,
                }
            };

            return Ok(StdDescriptorPoolAlloc {
                          pool: pool_arc.clone(),
                          set: Some(alloc),
                          descriptors: *layout.descriptors_count(),
                      });
        }

        // No existing pool can be used. Create a new one.
        // We use an arbitrary number of 40 sets and 40 times the requested descriptors.
        let count = layout.descriptors_count().clone() * 40;
        // Failure to allocate a new pool results in an error for the whole function because
        // there's no way we can recover from that.
        let mut new_pool = UnsafeDescriptorPool::new(self.device.clone(), &count, 40, true)?;

        let alloc = unsafe {
            match new_pool.alloc(Some(layout)) {
                Ok(mut sets) => sets.next().unwrap(),
                Err(DescriptorPoolAllocError::OutOfHostMemory) => {
                    return Err(OomError::OutOfHostMemory);
                },
                Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
                    return Err(OomError::OutOfDeviceMemory);
                },
                // A fragmented pool error can't happen at the first ever allocation.
                Err(DescriptorPoolAllocError::FragmentedPool) => unreachable!(),
                // Out of pool memory cannot happen at the first ever allocation.
                Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
            }
        };

        let pool_obj = Arc::new(Mutex::new(Pool {
                                               pool: new_pool,
                                               remaining_capacity: count -
                                                   *layout.descriptors_count(),
                                               remaining_sets_count: 40 - 1,
                                           }));

        pools.push(pool_obj.clone());

        Ok(StdDescriptorPoolAlloc {
               pool: pool_obj,
               set: Some(alloc),
               descriptors: *layout.descriptors_count(),
           })
    }
}

unsafe impl DeviceOwned for StdDescriptorPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

impl DescriptorPoolAlloc for StdDescriptorPoolAlloc {
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        self.set.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
        self.set.as_mut().unwrap()
    }
}

impl Drop for StdDescriptorPoolAlloc {
    // This is the destructor of a single allocation (not of the whole pool).
    fn drop(&mut self) {
        unsafe {
            let mut pool = self.pool.lock().unwrap();
            pool.pool.free(self.set.take()).unwrap();
            // Add back the capacity only after freeing, in case of a panic during the free.
            pool.remaining_sets_count += 1;
            pool.remaining_capacity += self.descriptors;
        }
    }
}
<commit_msg>Fix the StdDescriptorPool being destroyed too often (#801)<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::sync::Arc;
use std::sync::Mutex;

use OomError;
use descriptor::descriptor_set::DescriptorPool;
use descriptor::descriptor_set::DescriptorPoolAlloc;
use descriptor::descriptor_set::DescriptorPoolAllocError;
use descriptor::descriptor_set::DescriptorsCount;
use descriptor::descriptor_set::UnsafeDescriptorPool;
use descriptor::descriptor_set::UnsafeDescriptorSet;
use descriptor::descriptor_set::UnsafeDescriptorSetLayout;
use device::Device;
use device::DeviceOwned;

/// Standard implementation of a descriptor pool.
///
/// It is guaranteed that the `Arc<StdDescriptorPool>` is kept alive by its allocations. This is
/// desirable so that we can store a `Weak<StdDescriptorPool>`.
///
/// Whenever a set is allocated, this implementation will try to find a pool that has some space
/// for it. If there is one, allocate from it. If there is none, create a new pool whose capacity
/// is 40 sets and 40 times the requested descriptors. This number is arbitrary.
pub struct StdDescriptorPool {
    device: Arc<Device>,
    pools: Mutex<Vec<Arc<Mutex<Pool>>>>,
}

struct Pool {
    pool: UnsafeDescriptorPool,
    remaining_capacity: DescriptorsCount,
    remaining_sets_count: u32,
}

impl StdDescriptorPool {
    /// Builds a new `StdDescriptorPool`.
    pub fn new(device: Arc<Device>) -> StdDescriptorPool {
        StdDescriptorPool {
            device: device,
            pools: Mutex::new(Vec::new()),
        }
    }
}

/// A descriptor set allocated from a `StdDescriptorPool`.
pub struct StdDescriptorPoolAlloc {
    pool: Arc<Mutex<Pool>>,
    // The set. Inside an option so that we can extract it in the destructor.
    set: Option<UnsafeDescriptorSet>,
    // We need to keep track of this count in order to add it back to the capacity when freeing.
    descriptors: DescriptorsCount,
    // We keep the parent of the pool alive, otherwise it would be destroyed.
    pool_parent: Arc<StdDescriptorPool>,
}

unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
    type Alloc = StdDescriptorPoolAlloc;

    // TODO: eventually use a lock-free algorithm?
    fn alloc(&mut self, layout: &UnsafeDescriptorSetLayout)
             -> Result<StdDescriptorPoolAlloc, OomError> {
        let mut pools = self.pools.lock().unwrap();

        // Try find an existing pool with some free space.
        for pool_arc in pools.iter_mut() {
            let mut pool = pool_arc.lock().unwrap();

            if pool.remaining_sets_count == 0 {
                continue;
            }

            if !(pool.remaining_capacity >= *layout.descriptors_count()) {
                continue;
            }

            // Note that we decrease these values *before* trying to allocate from the pool.
            // If allocating from the pool results in an error, we just ignore it. In order to
            // avoid trying the same failing pool every time, we "pollute" it by reducing the
            // available space.
            pool.remaining_sets_count -= 1;
            pool.remaining_capacity -= *layout.descriptors_count();

            let alloc = unsafe {
                match pool.pool.alloc(Some(layout)) {
                    Ok(mut sets) => sets.next().unwrap(),
                    // An error can happen if we're out of memory, or if the pool is fragmented.
                    // We handle these errors by just ignoring this pool and trying the next ones.
                    Err(_) => continue,
                }
            };

            return Ok(StdDescriptorPoolAlloc {
                          pool: pool_arc.clone(),
                          set: Some(alloc),
                          descriptors: *layout.descriptors_count(),
                          pool_parent: self.clone(),
                      });
        }

        // No existing pool can be used. Create a new one.
        // We use an arbitrary number of 40 sets and 40 times the requested descriptors.
        let count = layout.descriptors_count().clone() * 40;
        // Failure to allocate a new pool results in an error for the whole function because
        // there's no way we can recover from that.
        let mut new_pool = UnsafeDescriptorPool::new(self.device.clone(), &count, 40, true)?;

        let alloc = unsafe {
            match new_pool.alloc(Some(layout)) {
                Ok(mut sets) => sets.next().unwrap(),
                Err(DescriptorPoolAllocError::OutOfHostMemory) => {
                    return Err(OomError::OutOfHostMemory);
                },
                Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
                    return Err(OomError::OutOfDeviceMemory);
                },
                // A fragmented pool error can't happen at the first ever allocation.
                Err(DescriptorPoolAllocError::FragmentedPool) => unreachable!(),
                // Out of pool memory cannot happen at the first ever allocation.
                Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
            }
        };

        let pool_obj = Arc::new(Mutex::new(Pool {
                                               pool: new_pool,
                                               remaining_capacity: count -
                                                   *layout.descriptors_count(),
                                               remaining_sets_count: 40 - 1,
                                           }));

        pools.push(pool_obj.clone());

        Ok(StdDescriptorPoolAlloc {
               pool: pool_obj,
               set: Some(alloc),
               descriptors: *layout.descriptors_count(),
               pool_parent: self.clone(),
           })
    }
}

unsafe impl DeviceOwned for StdDescriptorPool {
    #[inline]
    fn device(&self) -> &Arc<Device> {
        &self.device
    }
}

impl DescriptorPoolAlloc for StdDescriptorPoolAlloc {
    #[inline]
    fn inner(&self) -> &UnsafeDescriptorSet {
        self.set.as_ref().unwrap()
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
        self.set.as_mut().unwrap()
    }
}

impl Drop for StdDescriptorPoolAlloc {
    // This is the destructor of a single allocation (not of the whole pool).
    fn drop(&mut self) {
        unsafe {
            let mut pool = self.pool.lock().unwrap();
            pool.pool.free(self.set.take()).unwrap();
            // Add back the capacity only after freeing, in case of a panic during the free.
            pool.remaining_sets_count += 1;
            pool.remaining_capacity += self.descriptors;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::iter;
    use std::sync::Arc;
    use descriptor::descriptor::DescriptorDesc;
    use descriptor::descriptor::DescriptorDescTy;
    use descriptor::descriptor::ShaderStages;
    use descriptor::descriptor_set::DescriptorPool;
    use descriptor::descriptor_set::StdDescriptorPool;
    use descriptor::descriptor_set::UnsafeDescriptorSetLayout;

    #[test]
    fn desc_pool_kept_alive() {
        // Test that the `StdDescriptorPool` is kept alive by its allocations.
        let (device, _) = gfx_dev_and_queue!();

        let desc = DescriptorDesc {
            ty: DescriptorDescTy::Sampler,
            array_count: 1,
            stages: ShaderStages::all(),
            readonly: false,
        };
        let layout = UnsafeDescriptorSetLayout::new(device.clone(), iter::once(Some(desc))).unwrap();

        let mut pool = Arc::new(StdDescriptorPool::new(device));
        let pool_weak = Arc::downgrade(&pool);
        let alloc = pool.alloc(&layout);
        drop(pool);
        assert!(pool_weak.upgrade().is_some());
    }
}
<|endoftext|>


<commit_before>//! Reader and writer for the refFlat format.
//!
//! The refFlat format is a transcript-oriented format in which each
//! transcript is denoted in a single line. It is used most prominently
//! by the [picard suite tools](https://broadinstitute.github.io/picard/)
//!
//! A minimum specification of the columns can be found here:
//! https://genome.ucsc.edu/goldenPath/gbdDescriptionsOld.html#RefFlat

use std::cmp::{max, min};
use std::collections::HashMap;
use std::convert::AsRef;
use std::io;
use std::fs;
use std::path::Path;
use std::str::FromStr;

use csv;
use itertools::{GroupBy, Itertools};

use feature::FeatureError;
use {Coord, Gene, GBuilder, Strand, Transcript, TBuilder, Error};

pub type RefFlatRow = (String, String, String, char, u64, u64, u64, u64, usize, String, String);

pub struct RefFlatRecord {
    pub gene_id: String,
    pub transcript_name: String,
    pub seq_name: String,
    pub strand_char: char,
    pub trx_start: u64,
    pub trx_end: u64,
    pub coding_start: u64,
    pub coding_end: u64,
    pub num_exons: usize,
    pub exon_starts: String,
    pub exon_ends: String,
}

impl RefFlatRecord {
    pub fn new(row: RefFlatRow) -> RefFlatRecord {
        RefFlatRecord {
            gene_id: row.0,
            transcript_name: row.1,
            seq_name: row.2,
            strand_char: row.3,
            trx_start: row.4,
            trx_end: row.5,
            coding_start: row.6,
            coding_end: row.7,
            num_exons: row.8,
            exon_starts: row.9,
            exon_ends: row.10,
        }
    }

    pub fn to_transcript(self) -> Result<Transcript, Error> {
        self.to_tupled_transcript().map(|(_, trx)| trx)
    }

    fn to_tupled_transcript(self) -> Result<(String, Transcript), Error> {

        let exon_coords = self.zip_raw_exon_coords();
        if exon_coords.len() != self.num_exons {
            return Err(Error::RefFlat(
                "number of exon and exon coordinates mismatch"));
        }

        let strand = Strand::from_char(&self.strand_char)
            .map_err(FeatureError::from)
            .map_err(Error::from)?;

        let coding_coord =
            if self.coding_start != self.coding_end {
                Some((self.coding_start, self.coding_end))
            } else {
                None
            };

        let gene_id = self.gene_id;
        TBuilder::new(self.seq_name, self.trx_start, self.trx_end)
            .id(self.transcript_name)
            .strand(strand)
            .coords(exon_coords, coding_coord)
            .coding_incl_stop(true)
            .build()
            .map_err(Error::from)
            .map(|trx| (gene_id, trx))
    }

    #[inline]
    fn zip_raw_exon_coords(&self) -> Vec<Coord<u64>> {
        let exon_starts = self.exon_starts
            .split(',').filter_map(|item| u64::from_str(item).ok());
        let exon_ends = self.exon_ends
            .split(',').filter_map(|item| u64::from_str(item).ok());
        exon_starts.zip(exon_ends).collect()
    }
}

pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl<R: io::Read> Reader<R> {

    pub fn from_reader(in_reader: R) -> Reader<R> {
        Reader {
            inner: csv::Reader::from_reader(in_reader)
                .delimiter(b'\t')
                .has_headers(false)
        }
    }

    pub fn records<'a>(&'a mut self) -> RefFlatRecords<'a, R> {
        RefFlatRecords {
            inner: self.inner.decode()
        }
    }

    pub fn transcripts<'a>(&'a mut self) -> RefFlatTranscripts<'a, R> {
        RefFlatTranscripts {
            inner: self.records()
        }
    }

    pub fn genes<'a>(&'a mut self) -> RefFlatGenes<'a, R> {
        RefFlatGenes {
            inner: self.records().group_by(groupf),
        }
    }
}

impl Reader<fs::File> {
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::from_reader)
    }
}

pub struct RefFlatRecords<'a, R: 'a> where R: io::Read {
    inner: csv::DecodedRecords<'a, R, RefFlatRow>,
}

impl<'a, R> Iterator for RefFlatRecords<'a, R> where R: io::Read {

    type Item = Result<RefFlatRecord, Error>;

    fn next(&mut self) -> Option<Result<RefFlatRecord, Error>> {
        self.inner.next()
            .map(|row| {
                row.or_else(|err| Err(Error::from(err)))
                    .map(RefFlatRecord::new)
            })
    }
}

pub struct RefFlatTranscripts<'a, R: 'a> where R: io::Read {
    inner: RefFlatRecords<'a, R>,
}

impl<'a, R> Iterator for RefFlatTranscripts<'a, R> where R: io::Read {

    type Item = Result<Transcript, Error>;

    fn next(&mut self) -> Option<Result<Transcript, Error>> {
        self.inner.next()
            .map(|record| record.and_then(|rec| rec.to_transcript()))
    }
}

pub struct RefFlatGenes<'a, R: 'a> where R: io::Read, {
    inner: GroupBy<GroupKey, RefFlatRecords<'a, R>, GroupFunc>,
}

impl<'a, R> Iterator for RefFlatGenes<'a, R> where R: io::Read {

    type Item = Result<Gene, Error>;

    fn next(&mut self) -> Option<Result<Gene, Error>> {
        self.inner.into_iter()
            .map(|(okey, records)| {
                match okey {
                    Some((gid, seq_name, strand_char)) => {
                        let mut transcripts = HashMap::new();
                        let (mut gene_start, mut gene_end) = (u64::max_value(), u64::min_value());
                        for record in records {
                            let transcript = record.and_then(|rec| rec.to_transcript())?;
                            gene_start = min(gene_start, transcript.interval().start);
                            gene_end = max(gene_end, transcript.interval().end);
                            let tid = transcript.id.clone()
                                .ok_or(Error::RefFlat("transcript does not have ID"))?;
                            transcripts.insert(tid, transcript);
                        }
                        GBuilder::new(seq_name, gene_start, gene_end)
                            .id(gid)
                            .strand_char(strand_char)
                            .transcripts(transcripts)
                            .build()
                    },
                    None => Err(records.filter_map(|x| x.err()).next().unwrap())
                }
            }).next()
    }
}

type GroupKey = Option<(String, String, char)>;

type GroupFunc = fn(&Result<RefFlatRecord, Error>) -> GroupKey;

fn groupf(result: &Result<RefFlatRecord, Error>) -> GroupKey {
    result.as_ref().ok()
        .map(|ref res| (res.gene_id.clone(), res.seq_name.clone(), res.strand_char.clone()))
}
<commit_msg>Remove to_tupled_transcript and store gene_id as transcript attribute<commit_after>//! Reader and writer for the refFlat format.
//!
//! The refFlat format is a transcript-oriented format in which each
//! transcript is denoted in a single line. It is used most prominently
//! by the [picard suite tools](https://broadinstitute.github.io/picard/)
//!
//! A minimum specification of the columns can be found here:
//! https://genome.ucsc.edu/goldenPath/gbdDescriptionsOld.html#RefFlat

use std::cmp::{max, min};
use std::collections::HashMap;
use std::convert::AsRef;
use std::io;
use std::fs;
use std::path::Path;
use std::str::FromStr;

use csv;
use itertools::{GroupBy, Itertools};

use feature::FeatureError;
use {Coord, Gene, GBuilder, Strand, Transcript, TBuilder, Error};

pub type RefFlatRow = (String, String, String, char, u64, u64, u64, u64, usize, String, String);

pub struct RefFlatRecord {
    pub gene_id: String,
    pub transcript_name: String,
    pub seq_name: String,
    pub strand_char: char,
    pub trx_start: u64,
    pub trx_end: u64,
    pub coding_start: u64,
    pub coding_end: u64,
    pub num_exons: usize,
    pub exon_starts: String,
    pub exon_ends: String,
}

impl RefFlatRecord {
    pub fn new(row: RefFlatRow) -> RefFlatRecord {
        RefFlatRecord {
            gene_id: row.0,
            transcript_name: row.1,
            seq_name: row.2,
            strand_char: row.3,
            trx_start: row.4,
            trx_end: row.5,
            coding_start: row.6,
            coding_end: row.7,
            num_exons: row.8,
            exon_starts: row.9,
            exon_ends: row.10,
        }
    }

    pub fn to_transcript(self) -> Result<Transcript, Error> {

        let exon_coords = self.zip_raw_exon_coords();
        if exon_coords.len() != self.num_exons {
            return Err(Error::RefFlat(
                "number of exon and exon coordinates mismatch"));
        }

        let strand = Strand::from_char(&self.strand_char)
            .map_err(FeatureError::from)
            .map_err(Error::from)?;

        let coding_coord =
            if self.coding_start != self.coding_end {
                Some((self.coding_start, self.coding_end))
            } else {
                None
            };

        let mut attribs = HashMap::new();
        attribs.insert("gene_id".to_owned(), self.gene_id);
        TBuilder::new(self.seq_name, self.trx_start, self.trx_end)
            .id(self.transcript_name)
            .strand(strand)
            .coords(exon_coords, coding_coord)
            .coding_incl_stop(true)
            .attributes(attribs)
            .build()
            .map_err(Error::from)
    }

    #[inline]
    fn zip_raw_exon_coords(&self) -> Vec<Coord<u64>> {
        let exon_starts = self.exon_starts
            .split(',').filter_map(|item| u64::from_str(item).ok());
        let exon_ends = self.exon_ends
            .split(',').filter_map(|item| u64::from_str(item).ok());
        exon_starts.zip(exon_ends).collect()
    }
}

pub struct Reader<R: io::Read> {
    inner: csv::Reader<R>,
}

impl<R: io::Read> Reader<R> {

    pub fn from_reader(in_reader: R) -> Reader<R> {
        Reader {
            inner: csv::Reader::from_reader(in_reader)
                .delimiter(b'\t')
                .has_headers(false)
        }
    }

    pub fn records<'a>(&'a mut self) -> RefFlatRecords<'a, R> {
        RefFlatRecords {
            inner: self.inner.decode()
        }
    }

    pub fn transcripts<'a>(&'a mut self) -> RefFlatTranscripts<'a, R> {
        RefFlatTranscripts {
            inner: self.records()
        }
    }

    pub fn genes<'a>(&'a mut self) -> RefFlatGenes<'a, R> {
        RefFlatGenes {
            inner: self.records().group_by(groupf),
        }
    }
}

impl Reader<fs::File> {
    pub fn from_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
        fs::File::open(path).map(Reader::from_reader)
    }
}

pub struct RefFlatRecords<'a, R: 'a> where R: io::Read {
    inner: csv::DecodedRecords<'a, R, RefFlatRow>,
}

impl<'a, R> Iterator for RefFlatRecords<'a, R> where R: io::Read {

    type Item = Result<RefFlatRecord, Error>;

    fn next(&mut self) -> Option<Result<RefFlatRecord, Error>> {
        self.inner.next()
            .map(|row| {
                row.or_else(|err| Err(Error::from(err)))
                    .map(RefFlatRecord::new)
            })
    }
}

pub struct RefFlatTranscripts<'a, R: 'a> where R: io::Read {
    inner: RefFlatRecords<'a, R>,
}

impl<'a, R> Iterator for RefFlatTranscripts<'a, R> where R: io::Read {

    type Item = Result<Transcript, Error>;

    fn next(&mut self) -> Option<Result<Transcript, Error>> {
        self.inner.next()
            .map(|record| record.and_then(|rec| rec.to_transcript()))
    }
}

pub struct RefFlatGenes<'a, R: 'a> where R: io::Read, {
    inner: GroupBy<GroupKey, RefFlatRecords<'a, R>, GroupFunc>,
}

impl<'a, R> Iterator for RefFlatGenes<'a, R> where R: io::Read {

    type Item = Result<Gene, Error>;

    fn next(&mut self) -> Option<Result<Gene, Error>> {
        self.inner.into_iter()
            .map(|(okey, records)| {
                match okey {
                    Some((gid, seq_name, strand_char)) => {
                        let mut transcripts = HashMap::new();
                        let (mut gene_start, mut gene_end) = (u64::max_value(), u64::min_value());
                        for record in records {
                            let transcript = record.and_then(|rec| rec.to_transcript())?;
                            gene_start = min(gene_start, transcript.interval().start);
                            gene_end = max(gene_end, transcript.interval().end);
                            let tid = transcript.id.clone()
                                .ok_or(Error::RefFlat("transcript does not have ID"))?;
                            transcripts.insert(tid, transcript);
                        }
                        GBuilder::new(seq_name, gene_start, gene_end)
                            .id(gid)
                            .strand_char(strand_char)
                            .transcripts(transcripts)
                            .build()
                    },
                    None => Err(records.filter_map(|x| x.err()).next().unwrap())
                }
            }).next()
    }
}

type GroupKey = Option<(String, String, char)>;

type GroupFunc = fn(&Result<RefFlatRecord, Error>) -> GroupKey;

fn groupf(result: &Result<RefFlatRecord, Error>) -> GroupKey {
    result.as_ref().ok()
        .map(|ref res| (res.gene_id.clone(), res.seq_name.clone(), res.strand_char.clone()))
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use error::RuntimeError;

use sys::x11;
use sys::xcb;
use sys::egl;
use sys::gl;

use super::window::LinuxWindow;

pub struct LinuxApplication {
   pub x11_handler: X11Handler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
   pub egl_handler: EglHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_handler = try!(X11Handler::new());
      let connection = try!(ConnectionHandler::new(&x11_handler));
      let screen = try!(ScreenHandler::new(&x11_handler, &connection));
      let egl_handler = try!(EglHandler::new(&x11_handler));

      gl::load(egl::Loader::new());
      gl::reset_pixelstore_alignment();

      Ok(LinuxApplication {
         x11_handler: x11_handler,
         connection: connection,
         screen: screen,
         egl_handler: egl_handler,
      })
   }

   #[inline]
   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }

   pub fn create_os_window(
      &self, title: &str, x: u32, y: u32, width: u32, height: u32
   ) -> Result<LinuxWindow, RuntimeError> {
      let xcb_window = try!(self.screen.create_window(
         &self.connection, x, y, width, height
      ));

      let surface = try!(self.egl_handler.create_surface(&xcb_window));

      try!(self.egl_handler.make_current(&surface));

      Ok(LinuxWindow::new(xcb_window, surface, title))
   }
}

pub struct X11Handler {
   pub display: x11::Display,
}

impl X11Handler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11Handler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: Rc<xcb::Connection>,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(x11_handler: &X11Handler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: Rc::new(try!(x11_handler.connection()))
      })
   }

   #[inline]
   pub fn screen_of_display(&self, x11_handler: &X11Handler) -> Result<xcb::Screen, RuntimeError> {
      let screen_id = x11_handler.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(x11_handler: &X11Handler, connection: &ConnectionHandler) -> Result<Self, RuntimeError> {
      Ok(ScreenHandler {
         screen: try!(connection.screen_of_display(x11_handler))
      })
   }

   #[inline]
   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }

   #[inline]
   pub fn create_window(
      &self, connection: &ConnectionHandler, x: u32, y: u32, width: u32, height: u32
   ) -> Result<xcb::Window, RuntimeError> {

      xcb::Window::create(
         &connection.connection, &self.screen, x, y, width, height,
      )
   }
}

pub struct EglHandler {
   pub display: egl::Display,
   pub version: egl::Version,
   pub config: egl::Config,
   pub context: egl::Context,
}

impl EglHandler {
   pub fn new(x11_handler: &X11Handler) -> Result<Self, RuntimeError> {
      try!(egl::bind_api(egl::API::OpenGL));

      let display = try!(egl::Display::from_native(&x11_handler.display));
      let version = try!(egl::initialize(&display));
      let config = try!(egl::choose_config(&display));
      let context = try!(egl::create_context(&display, &config));

      try!(egl::query_context(&display, &context));

      Ok(EglHandler {
         display: display,
         version: version,
         config: config,
         context: context,
      })
   }

   #[inline]
   pub fn create_surface(&self, xcb_window: &xcb::Window) -> Result<egl::Surface, RuntimeError> {
      egl::create_window_surface(
         &self.display,
         &self.config,
         &xcb_window.window_id.id
      )
   }

   #[inline]
   pub fn make_current(&self, surface: &egl::Surface) -> Result<(), RuntimeError> {
      egl::make_current(
         &self.display,
         surface,
         surface,
         &self.context
      )
   }
}
<commit_msg>Reset EGL swap interval on window creation<commit_after>use std::rc::Rc;

use error::RuntimeError;

use sys::x11;
use sys::xcb;
use sys::egl;
use sys::gl;

use super::window::LinuxWindow;

pub struct LinuxApplication {
   pub x11_handler: X11Handler,
   pub connection: ConnectionHandler,
   pub screen: ScreenHandler,
   pub egl_handler: EglHandler,
}

impl LinuxApplication {
   pub fn new() -> Result<Self, RuntimeError> {
      let x11_handler = try!(X11Handler::new());
      let connection = try!(ConnectionHandler::new(&x11_handler));
      let screen = try!(ScreenHandler::new(&x11_handler, &connection));
      let egl_handler = try!(EglHandler::new(&x11_handler));

      gl::load(egl::Loader::new());
      gl::reset_pixelstore_alignment();

      Ok(LinuxApplication {
         x11_handler: x11_handler,
         connection: connection,
         screen: screen,
         egl_handler: egl_handler,
      })
   }

   #[inline]
   pub fn screen_size(&self) -> (u32, u32) {
      self.screen.size()
   }

   pub fn create_os_window(
      &self, title: &str, x: u32, y: u32, width: u32, height: u32
   ) -> Result<LinuxWindow, RuntimeError> {
      let xcb_window = try!(self.screen.create_window(
         &self.connection, x, y, width, height
      ));

      let surface = try!(self.egl_handler.create_surface(&xcb_window));

      try!(self.egl_handler.make_current(&surface));

      try!(self.egl_handler.reset_swap_interval());

      Ok(LinuxWindow::new(xcb_window, surface, title))
   }
}

pub struct X11Handler {
   pub display: x11::Display,
}

impl X11Handler {
   #[inline]
   pub fn new() -> Result<Self, RuntimeError> {
      let display = try!(x11::Display::default());

      display.xcb_own_event_queue();

      Ok(X11Handler {
         display: display
      })
   }

   #[inline]
   pub fn connection(&self) -> Result<xcb::Connection, RuntimeError> {
      self.display.xcb_connection()
   }

   #[inline]
   pub fn screen_id(&self) -> x11::ScreenID {
      self.display.default_screen()
   }
}

pub struct ConnectionHandler {
   pub connection: Rc<xcb::Connection>,
}

impl ConnectionHandler {
   #[inline]
   pub fn new(x11_handler: &X11Handler) -> Result<Self, RuntimeError> {
      Ok(ConnectionHandler {
         connection: Rc::new(try!(x11_handler.connection()))
      })
   }

   #[inline]
   pub fn screen_of_display(&self, x11_handler: &X11Handler) -> Result<xcb::Screen, RuntimeError> {
      let screen_id = x11_handler.screen_id();

      self.connection.screen_of_display(&screen_id)
   }
}

pub struct ScreenHandler {
   pub screen: xcb::Screen,
}

impl ScreenHandler {
   #[inline]
   pub fn new(x11_handler: &X11Handler, connection: &ConnectionHandler) -> Result<Self, RuntimeError> {
      Ok(ScreenHandler {
         screen: try!(connection.screen_of_display(x11_handler))
      })
   }

   #[inline]
   pub fn size(&self) -> (u32, u32) {
      (
         self.screen.width_in_pixels() as u32,
         self.screen.height_in_pixels() as u32
      )
   }

   #[inline]
   pub fn create_window(
      &self, connection: &ConnectionHandler, x: u32, y: u32, width: u32, height: u32
   ) -> Result<xcb::Window, RuntimeError> {

      xcb::Window::create(
         &connection.connection, &self.screen, x, y, width, height,
      )
   }
}

pub struct EglHandler {
   pub display: egl::Display,
   pub version: egl::Version,
   pub config: egl::Config,
   pub context: egl::Context,
}

impl EglHandler {
   pub fn new(x11_handler: &X11Handler) -> Result<Self, RuntimeError> {
      try!(egl::bind_api(egl::API::OpenGL));

      let display = try!(egl::Display::from_native(&x11_handler.display));
      let version = try!(egl::initialize(&display));
      let config = try!(egl::choose_config(&display));
      let context = try!(egl::create_context(&display, &config));

      try!(egl::query_context(&display, &context));

      Ok(EglHandler {
         display: display,
         version: version,
         config: config,
         context: context,
      })
   }

   #[inline]
   pub fn create_surface(&self, xcb_window: &xcb::Window) -> Result<egl::Surface, RuntimeError> {
      egl::create_window_surface(
         &self.display,
         &self.config,
         &xcb_window.window_id.id
      )
   }

   #[inline]
   pub fn make_current(&self, surface: &egl::Surface) -> Result<(), RuntimeError> {
      egl::make_current(
         &self.display,
         surface,
         surface,
         &self.context
      )
   }

   #[inline]
   pub fn reset_swap_interval(&self) -> Result<(), RuntimeError> {
      egl::swap_interval(&self.display, 0)
   }
}
<|endoftext|>