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

use 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},
    RsCodegenResult, Use,
};
use crate::{
    conversion::{
        analysis::fun::{
            ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
            TraitMethodDetails, UnsafetyNeeded,
        },
        api::ImplBlockDetails,
        codegen_rs::lifetime::add_lifetime_to_all_params,
    },
    types::{Namespace, QualifiedName},
};
use crate::{
    conversion::{api::FuncToConvert, codegen_rs::lifetime::add_explicit_lifetime_if_necessary},
    types::make_ident,
};

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

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

pub(super) fn gen_function(
    ns: &Namespace,
    fun: FuncToConvert,
    analysis: FnAnalysis,
    cpp_call_name: String,
) -> 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_attr = fun.doc_attr;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let mut trait_impl_entry = None;
    let wrapper_unsafety = analysis.requires_unsafe.wrapper_token();
    let fn_generator = FnGenerator {
        param_details: &param_details,
        cxxbridge_name: &cxxbridge_name,
        rust_name: &rust_name,
        unsafety: &wrapper_unsafety,
        doc_attr: &doc_attr,
    };
    let mut materialization = match kind {
        FnKind::Method(..) | FnKind::TraitMethod { .. } => None,
        FnKind::Function => match analysis.rust_rename_strategy {
            RustRenameStrategy::RenameInOutputMod(alias) => {
                Some(Use::UsedFromCxxBridgeWithAlias(alias))
            }
            _ => Some(Use::UsedFromCxxBridge),
        },
    };
    let any_param_needs_rust_conversion = param_details
        .iter()
        .any(|pd| pd.conversion.rust_work_needed());
    let rust_wrapper_needed = match kind {
        FnKind::TraitMethod { .. } => true,
        FnKind::Method(..) => {
            any_param_needs_rust_conversion
                || cxxbridge_name != rust_name
                || wrapper_function_needed
        }
        _ => any_param_needs_rust_conversion,
    };
    if rust_wrapper_needed {
        match kind {
            FnKind::Method(ref type_name, MethodKind::Constructor) => {
                // Constructor.
                impl_entry = Some(fn_generator.generate_constructor_impl(type_name));
            }
            FnKind::Method(ref type_name, ref method_kind) => {
                // Method, or static method.
                impl_entry = Some(fn_generator.generate_method_impl(
                    matches!(
                        method_kind,
                        MethodKind::MakeUnique | MethodKind::Constructor
                    ),
                    type_name,
                    &ret_type,
                ));
            }
            FnKind::TraitMethod { ref details, .. } => {
                trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
            }
            _ => {
                // Generate plain old function
                materialization = Some(Use::Custom(fn_generator.generate_function_impl(&ret_type)));
            }
        }
    }
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // In very 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);

    // 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_attr
        #vis #bridge_unsafety fn #cxxbridge_name #lifetime_tokens ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_items: vec![extern_c_mod_item],
        bridge_items: Vec::new(),
        global_items: trait_impl_entry.into_iter().collect(),
        bindgen_mod_items: Vec::new(),
        impl_entry,
        materializations: materialization.into_iter().collect(),
        extern_rust_mod_items: Vec::new(),
    }
}

/// 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 Option<Unsafe>,
    doc_attr: &'a Option<Attribute>,
}

impl<'a> FnGenerator<'a> {
    fn generate_arg_lists(&self, avoid_self: bool) -> (Punctuated<FnArg, Comma>, Vec<TokenStream>) {
        let mut wrapper_params: Punctuated<FnArg, Comma> = Punctuated::new();
        let mut arg_list = Vec::new();

        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 param_mutability = pd.conversion.rust_conversion.requires_mutability();
            wrapper_params.push(parse_quote!(
                #param_mutability #wrapper_arg_name: #type_name
            ));
            arg_list.push(pd.conversion.rust_conversion(wrapper_arg_name));
        }
        (wrapper_params, arg_list)
    }

    /// Generate an 'impl Type { methods-go-here }' item
    fn generate_method_impl(
        &self,
        avoid_self: bool,
        impl_block_type_name: &QualifiedName,
        ret_type: &ReturnType,
    ) -> Box<ImplBlockDetails> {
        let (wrapper_params, arg_list) = self.generate_arg_lists(avoid_self);
        let (lifetime_tokens, wrapper_params, ret_type) =
            add_explicit_lifetime_if_necessary(self.param_details, wrapper_params, ret_type);
        let rust_name = make_ident(self.rust_name);
        let unsafety = self.unsafety;
        let doc_attr = self.doc_attr;
        let cxxbridge_name = self.cxxbridge_name;
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #doc_attr
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    cxxbridge::#cxxbridge_name ( #(#arg_list),* )
                }
            }),
            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) -> Item {
        let (mut wrapper_params, arg_list) = self.generate_arg_lists(details.avoid_self);
        if let Some(parameter_reordering) = &details.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);
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        let cxxbridge_name = self.cxxbridge_name;
        let trait_signature = &details.trait_signature;
        let trait_unsafety = &details.trait_unsafety;
        let impl_for_specifics = &details.impl_for_specifics;
        let method_name = &details.method_name;
        let call_body = quote! {
            cxxbridge::#cxxbridge_name ( #(#arg_list),* )
        };
        let call_body = if details.trait_call_is_unsafe {
            quote! {
                unsafe {
                    #call_body
                }
            }
        } else {
            call_body
        };
        parse_quote! {
            #trait_unsafety impl #lifetime_tokens #trait_signature for #impl_for_specifics {
                #doc_attr
                #unsafety fn #method_name ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }
        }
    }

    /// 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 (wrapper_params, arg_list) = self.generate_arg_lists(true);
        let mut wrapper_params: Punctuated<FnArg, Comma> =
            wrapper_params.into_iter().skip(1).collect();
        let ptr_arg_name = &arg_list[0];
        let rust_name = make_ident(&self.rust_name);
        let any_references = self.param_details.iter().any(|pd| pd.was_reference);
        let (lifetime_param, lifetime_addition) = if any_references {
            add_lifetime_to_all_params(&mut wrapper_params);
            (quote! { <'a> }, quote! { + 'a })
        } else {
            (quote! {}, quote! {})
        };
        let cxxbridge_name = self.cxxbridge_name;
        let body = quote! {
            autocxx::moveit::new::by_raw(move |#ptr_arg_name| {
                let #ptr_arg_name = #ptr_arg_name.get_unchecked_mut().as_mut_ptr();
                cxxbridge::#cxxbridge_name(#(#arg_list),* )
            })
        };
        let body = if self.unsafety.is_some() {
            // No need for `unsafe` inside the function
            body
        } else {
            quote! {
                unsafe { #body }
            }
        };
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #doc_attr
                pub #unsafety fn #rust_name #lifetime_param ( #wrapper_params ) -> impl autocxx::moveit::new::New<Output=Self> #lifetime_addition {
                    #body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate a function call wrapper
    fn generate_function_impl(&self, ret_type: &ReturnType) -> Box<Item> {
        let (wrapper_params, arg_list) = self.generate_arg_lists(false);
        let rust_name = make_ident(self.rust_name);
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        Box::new(Item::Fn(parse_quote! {
            #doc_attr
            pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#rust_name ( #(#arg_list),* )
            }
        }))
    }

    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>Fix problem with function calls<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use 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},
    RsCodegenResult, Use,
};
use crate::{
    conversion::{
        analysis::fun::{
            ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
            TraitMethodDetails, UnsafetyNeeded,
        },
        api::ImplBlockDetails,
        codegen_rs::lifetime::add_lifetime_to_all_params,
    },
    types::{Namespace, QualifiedName},
};
use crate::{
    conversion::{api::FuncToConvert, codegen_rs::lifetime::add_explicit_lifetime_if_necessary},
    types::make_ident,
};

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

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

pub(super) fn gen_function(
    ns: &Namespace,
    fun: FuncToConvert,
    analysis: FnAnalysis,
    cpp_call_name: String,
) -> 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_attr = fun.doc_attr;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let mut trait_impl_entry = None;
    let wrapper_unsafety = analysis.requires_unsafe.wrapper_token();
    let fn_generator = FnGenerator {
        param_details: &param_details,
        cxxbridge_name: &cxxbridge_name,
        rust_name: &rust_name,
        unsafety: &wrapper_unsafety,
        doc_attr: &doc_attr,
    };
    let mut materialization = match kind {
        FnKind::Method(..) | FnKind::TraitMethod { .. } => None,
        FnKind::Function => match analysis.rust_rename_strategy {
            RustRenameStrategy::RenameInOutputMod(alias) => {
                Some(Use::UsedFromCxxBridgeWithAlias(alias))
            }
            _ => Some(Use::UsedFromCxxBridge),
        },
    };
    let any_param_needs_rust_conversion = param_details
        .iter()
        .any(|pd| pd.conversion.rust_work_needed());
    let rust_wrapper_needed = match kind {
        FnKind::TraitMethod { .. } => true,
        FnKind::Method(..) => {
            any_param_needs_rust_conversion
                || cxxbridge_name != rust_name
                || wrapper_function_needed
        }
        _ => any_param_needs_rust_conversion,
    };
    if rust_wrapper_needed {
        match kind {
            FnKind::Method(ref type_name, MethodKind::Constructor) => {
                // Constructor.
                impl_entry = Some(fn_generator.generate_constructor_impl(type_name));
            }
            FnKind::Method(ref type_name, ref method_kind) => {
                // Method, or static method.
                impl_entry = Some(fn_generator.generate_method_impl(
                    matches!(
                        method_kind,
                        MethodKind::MakeUnique | MethodKind::Constructor
                    ),
                    type_name,
                    &ret_type,
                ));
            }
            FnKind::TraitMethod { ref details, .. } => {
                trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
            }
            _ => {
                // Generate plain old function
                materialization = Some(Use::Custom(fn_generator.generate_function_impl(&ret_type)));
            }
        }
    }
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // In very 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);

    // 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_attr
        #vis #bridge_unsafety fn #cxxbridge_name #lifetime_tokens ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_items: vec![extern_c_mod_item],
        bridge_items: Vec::new(),
        global_items: trait_impl_entry.into_iter().collect(),
        bindgen_mod_items: Vec::new(),
        impl_entry,
        materializations: materialization.into_iter().collect(),
        extern_rust_mod_items: Vec::new(),
    }
}

/// 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 Option<Unsafe>,
    doc_attr: &'a Option<Attribute>,
}

impl<'a> FnGenerator<'a> {
    fn generate_arg_lists(&self, avoid_self: bool) -> (Punctuated<FnArg, Comma>, Vec<TokenStream>) {
        let mut wrapper_params: Punctuated<FnArg, Comma> = Punctuated::new();
        let mut arg_list = Vec::new();

        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 param_mutability = pd.conversion.rust_conversion.requires_mutability();
            wrapper_params.push(parse_quote!(
                #param_mutability #wrapper_arg_name: #type_name
            ));
            arg_list.push(pd.conversion.rust_conversion(wrapper_arg_name));
        }
        (wrapper_params, arg_list)
    }

    /// Generate an 'impl Type { methods-go-here }' item
    fn generate_method_impl(
        &self,
        avoid_self: bool,
        impl_block_type_name: &QualifiedName,
        ret_type: &ReturnType,
    ) -> Box<ImplBlockDetails> {
        let (wrapper_params, arg_list) = self.generate_arg_lists(avoid_self);
        let (lifetime_tokens, wrapper_params, ret_type) =
            add_explicit_lifetime_if_necessary(self.param_details, wrapper_params, ret_type);
        let rust_name = make_ident(self.rust_name);
        let unsafety = self.unsafety;
        let doc_attr = self.doc_attr;
        let cxxbridge_name = self.cxxbridge_name;
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #doc_attr
                pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
                    cxxbridge::#cxxbridge_name ( #(#arg_list),* )
                }
            }),
            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) -> Item {
        let (mut wrapper_params, arg_list) = self.generate_arg_lists(details.avoid_self);
        if let Some(parameter_reordering) = &details.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);
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        let cxxbridge_name = self.cxxbridge_name;
        let trait_signature = &details.trait_signature;
        let trait_unsafety = &details.trait_unsafety;
        let impl_for_specifics = &details.impl_for_specifics;
        let method_name = &details.method_name;
        let call_body = quote! {
            cxxbridge::#cxxbridge_name ( #(#arg_list),* )
        };
        let call_body = if details.trait_call_is_unsafe {
            quote! {
                unsafe {
                    #call_body
                }
            }
        } else {
            call_body
        };
        parse_quote! {
            #trait_unsafety impl #lifetime_tokens #trait_signature for #impl_for_specifics {
                #doc_attr
                #unsafety fn #method_name ( #wrapper_params ) #ret_type {
                    #call_body
                }
            }
        }
    }

    /// 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 (wrapper_params, arg_list) = self.generate_arg_lists(true);
        let mut wrapper_params: Punctuated<FnArg, Comma> =
            wrapper_params.into_iter().skip(1).collect();
        let ptr_arg_name = &arg_list[0];
        let rust_name = make_ident(&self.rust_name);
        let any_references = self.param_details.iter().any(|pd| pd.was_reference);
        let (lifetime_param, lifetime_addition) = if any_references {
            add_lifetime_to_all_params(&mut wrapper_params);
            (quote! { <'a> }, quote! { + 'a })
        } else {
            (quote! {}, quote! {})
        };
        let cxxbridge_name = self.cxxbridge_name;
        let body = quote! {
            autocxx::moveit::new::by_raw(move |#ptr_arg_name| {
                let #ptr_arg_name = #ptr_arg_name.get_unchecked_mut().as_mut_ptr();
                cxxbridge::#cxxbridge_name(#(#arg_list),* )
            })
        };
        let body = if self.unsafety.is_some() {
            // No need for `unsafe` inside the function
            body
        } else {
            quote! {
                unsafe { #body }
            }
        };
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        Box::new(ImplBlockDetails {
            item: ImplItem::Method(parse_quote! {
                #doc_attr
                pub #unsafety fn #rust_name #lifetime_param ( #wrapper_params ) -> impl autocxx::moveit::new::New<Output=Self> #lifetime_addition {
                    #body
                }
            }),
            ty: impl_block_type_name.get_final_ident(),
        })
    }

    /// Generate a function call wrapper
    fn generate_function_impl(&self, ret_type: &ReturnType) -> Box<Item> {
        let (wrapper_params, arg_list) = self.generate_arg_lists(false);
        let rust_name = make_ident(self.rust_name);
        let cxxbridge_name = self.cxxbridge_name;
        let doc_attr = self.doc_attr;
        let unsafety = self.unsafety;
        Box::new(Item::Fn(parse_quote! {
            #doc_attr
            pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#cxxbridge_name ( #(#arg_list),* )
            }
        }))
    }

    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>extern crate env_logger;

extern crate gluon;
extern crate tensile;

use gluon::vm::api::{Hole, OpaqueValue};
use gluon::{new_vm, Compiler, Thread};

use std::io::Read;
use std::fmt;
use std::fs::{read_dir, File};
use std::path::PathBuf;
use std::error::Error;

#[derive(Debug)]
pub struct StringError(String);

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for StringError {
    fn description(&self) -> &str {
        &self.0
    }
}

#[test]
fn main() {
    if let Err(err) = main_() {
        assert!(false, "{}", err);
    }
}

fn test_files(path: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let dir = read_dir(path)?;
    let paths: Vec<_> = dir.filter_map(|f| {
        f.ok().and_then(|f| {
            let path = f.path();
            if path.extension().and_then(|e| e.to_str()) == Some("glu") {
                Some(path)
            } else {
                None
            }
        })
    }).collect();
    assert!(!paths.is_empty(), "Expected test files");
    Ok(paths)
}

fn main_() -> Result<(), Box<Error>> {
    let _ = ::env_logger::init();
    let args: Vec<_> = ::std::env::args().collect();
    let filter = if args.len() > 1 && args.last().unwrap() != "main" {
        args.last()
    } else {
        None
    };

    let vm = new_vm();
    Compiler::new()
        .load_file_async(&vm, "std/prelude.glu")
        .sync_or_error()?;

    let iter = test_files("tests/pass")?.into_iter().filter(|filename| {
        filter.map_or(true, |filter| filename.to_string_lossy().contains(filter))
    });

    let mut pass_tests = Vec::new();

    for filename in iter {
        let name = filename.to_str().unwrap_or("<unknown>").to_owned();

        let vm = vm.new_thread().unwrap();

        pass_tests.push(tensile::test(name.clone(), move || -> Result<(), String> {
            let mut compiler = Compiler::new();

            let mut file = File::open(&filename).map_err(|err| err.to_string())?;
            let mut text = String::new();
            file.read_to_string(&mut text)
                .map_err(|err| err.to_string())?;
            compiler
                .run_expr_async::<OpaqueValue<&Thread, Hole>>(&vm, &name, &text)
                .sync_or_error()
                .map_err(|err| err.to_string())?;
            Ok(())
        }));
    }

    let iter = test_files("tests/fail")?.into_iter().filter(|filename| {
        filter.map_or(true, |filter| filename.to_string_lossy().contains(filter))
    });

    let mut compiler = Compiler::new();
    let mut text = String::new();

    for filename in iter {
        let mut file = File::open(&filename)?;
        text.clear();
        file.read_to_string(&mut text)?;
        let name = filename.to_str().unwrap_or("<unknown>");
        match compiler
            .run_expr_async::<OpaqueValue<&Thread, Hole>>(&vm, name, &text)
            .sync_or_error()
        {
            Ok(x) => {
                return Err(
                    StringError(format!(
                        "Expected test '{}' to fail got {:?}",
                        filename.to_str().unwrap(),
                        x
                    )).into(),
                )
            }
            Err(_) => (),
        }
    }

    tensile::console_runner(
        tensile::group("main", vec![tensile::group("pass", pass_tests)]),
        &tensile::Options::default().jobs(Some(3)),
    ).unwrap();
    Ok(())
}
<commit_msg>refactor: Add the the fail tests as tensile tests<commit_after>extern crate env_logger;

extern crate gluon;
extern crate tensile;

use gluon::base::types::ArcType;
use gluon::vm::api::{Hole, OpaqueValue};
use gluon::{new_vm, Compiler, Thread};

use std::io::Read;
use std::fmt;
use std::fs::{read_dir, File};
use std::path::{Path, PathBuf};
use std::error::Error;

#[derive(Debug)]
pub struct StringError(String);

impl fmt::Display for StringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Error for StringError {
    fn description(&self) -> &str {
        &self.0
    }
}

#[test]
fn main() {
    if let Err(err) = main_() {
        assert!(false, "{}", err);
    }
}

fn test_files(path: &str) -> Result<Vec<PathBuf>, Box<Error>> {
    let dir = read_dir(path)?;
    let paths: Vec<_> = dir.filter_map(|f| {
        f.ok().and_then(|f| {
            let path = f.path();
            if path.extension().and_then(|e| e.to_str()) == Some("glu") {
                Some(path)
            } else {
                None
            }
        })
    }).collect();
    assert!(!paths.is_empty(), "Expected test files");
    Ok(paths)
}

fn run_file<'t>(
    vm: &'t Thread,
    name: &str,
    filename: &Path,
) -> Result<(OpaqueValue<&'t Thread, Hole>, ArcType), String> {
    let mut compiler = Compiler::new();

    let mut file = File::open(&filename).map_err(|err| err.to_string())?;
    let mut text = String::new();
    file.read_to_string(&mut text)
        .map_err(|err| err.to_string())?;
    compiler
        .run_expr_async::<OpaqueValue<&Thread, Hole>>(&vm, &name, &text)
        .sync_or_error()
        .map_err(|err| err.to_string())
}

fn main_() -> Result<(), Box<Error>> {
    let _ = ::env_logger::init();
    let args: Vec<_> = ::std::env::args().collect();
    let filter = if args.len() > 1 && args.last().unwrap() != "main" {
        args.last()
    } else {
        None
    };

    let vm = new_vm();
    Compiler::new()
        .load_file_async(&vm, "std/prelude.glu")
        .sync_or_error()?;

    let iter = test_files("tests/pass")?.into_iter().filter(|filename| {
        filter.map_or(true, |filter| filename.to_string_lossy().contains(filter))
    });

    let pass_tests = iter.map(|filename| {
        let name = filename.to_str().unwrap_or("<unknown>").to_owned();

        let vm = vm.new_thread().unwrap();

        tensile::test(name.clone(), move || -> Result<(), String> {
            run_file(&vm, &name, &filename).map(|_| ())
        })
    }).collect();

    let iter = test_files("tests/fail")?.into_iter().filter(|filename| {
        filter.map_or(true, |filter| filename.to_string_lossy().contains(filter))
    });

    let fail_tests = iter.map(|filename| {
        let name = filename.to_str().unwrap_or("<unknown>").to_owned();

        let vm = vm.new_thread().unwrap();

        tensile::test(name.clone(), move || -> Result<(), String> {
            match run_file(&vm, &name, &filename) {
                Ok(x) => Err(format!(
                    "Expected test '{}' to fail got {:?}",
                    filename.to_str().unwrap(),
                    x
                )),
                Err(_) => Ok(()),
            }
        })
    }).collect();

    tensile::console_runner(
        tensile::group(
            "main",
            vec![
                tensile::group("pass", pass_tests),
                tensile::group("fail", fail_tests),
            ],
        ),
        &tensile::Options::default(),
    ).unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>extern crate translator;

#[test]
fn empty()
{
	let translator = translator::Translator::new();

	assert_eq!("", translator.translate(""));
	assert_eq!(" ", translator.translate(" "));
	assert_eq!("  ", translator.translate("  "));
	assert_eq!("   ", translator.translate("   "));
}

#[test]
fn letters()
{
	let translator = translator::Translator::new();

	assert_eq!("а", translator.translate("a"));
	assert_eq!("б", translator.translate("b"));
	assert_eq!("в", translator.translate("v"));
	assert_eq!("г", translator.translate("g"));
	assert_eq!("д", translator.translate("d"));
	assert_eq!("е", translator.translate("e"));
	assert_eq!("ё", translator.translate("jo"));
	assert_eq!("ж", translator.translate("zh"));
	assert_eq!("з", translator.translate("z"));
	assert_eq!("и", translator.translate("i"));
	assert_eq!("й", translator.translate("j"));
	assert_eq!("к", translator.translate("k"));
	assert_eq!("л", translator.translate("l"));
	assert_eq!("м", translator.translate("m"));
	assert_eq!("н", translator.translate("n"));
	assert_eq!("о", translator.translate("o"));
	assert_eq!("п", translator.translate("p"));
	assert_eq!("р", translator.translate("r"));
	assert_eq!("с", translator.translate("s"));
	assert_eq!("т", translator.translate("t"));
	assert_eq!("у", translator.translate("u"));
	assert_eq!("ф", translator.translate("f"));
	assert_eq!("х", translator.translate("h"));
	assert_eq!("ц", translator.translate("c"));
	assert_eq!("ч", translator.translate("ch"));
	assert_eq!("ш", translator.translate("sh"));
	assert_eq!("щ", translator.translate("shh"));
	assert_eq!("ъ", translator.translate("#"));
	assert_eq!("ы", translator.translate("y"));
	assert_eq!("ь", translator.translate("'"));
	assert_eq!("э", translator.translate("je"));
	assert_eq!("ю", translator.translate("ju"));
	assert_eq!("я", translator.translate("ja"));
}

#[test]
fn capital_letters()
{
	let translator = translator::Translator::new();

	assert_eq!("А", translator.translate("A"));
	assert_eq!("Б", translator.translate("B"));
	assert_eq!("В", translator.translate("V"));
	assert_eq!("Г", translator.translate("G"));
	assert_eq!("Д", translator.translate("D"));
	assert_eq!("Е", translator.translate("E"));
	assert_eq!("Ё", translator.translate("JO"));
	assert_eq!("Ж", translator.translate("ZH"));
	assert_eq!("З", translator.translate("Z"));
	assert_eq!("И", translator.translate("I"));
	assert_eq!("Й", translator.translate("J"));
	assert_eq!("К", translator.translate("K"));
	assert_eq!("Л", translator.translate("L"));
	assert_eq!("М", translator.translate("M"));
	assert_eq!("Н", translator.translate("N"));
	assert_eq!("О", translator.translate("O"));
	assert_eq!("П", translator.translate("P"));
	assert_eq!("Р", translator.translate("R"));
	assert_eq!("С", translator.translate("S"));
	assert_eq!("Т", translator.translate("T"));
	assert_eq!("У", translator.translate("U"));
	assert_eq!("Ф", translator.translate("F"));
	assert_eq!("Х", translator.translate("X"));
	assert_eq!("Х", translator.translate("H")); // TODO !!!
	assert_eq!("Ц", translator.translate("C"));
	assert_eq!("Ч", translator.translate("CH"));
	assert_eq!("Ш", translator.translate("SH"));
	assert_eq!("Щ", translator.translate("SHH"));
	assert_eq!("Ъ", translator.translate("##"));
	assert_eq!("Ы", translator.translate("Y"));
	assert_eq!("Ь", translator.translate("''"));
	assert_eq!("Э", translator.translate("JE"));
	assert_eq!("Ю", translator.translate("JU"));
	assert_eq!("Я", translator.translate("JA"));
}

#[test]
fn words()
{
	let translator = translator::Translator::new();

	assert_eq!("Привет", translator.translate("Privet"));
}
<commit_msg>TODO has been removed<commit_after>extern crate translator;

#[test]
fn empty()
{
	let translator = translator::Translator::new();

	assert_eq!("", translator.translate(""));
	assert_eq!(" ", translator.translate(" "));
	assert_eq!("  ", translator.translate("  "));
	assert_eq!("   ", translator.translate("   "));
}

#[test]
fn letters()
{
	let translator = translator::Translator::new();

	assert_eq!("а", translator.translate("a"));
	assert_eq!("б", translator.translate("b"));
	assert_eq!("в", translator.translate("v"));
	assert_eq!("г", translator.translate("g"));
	assert_eq!("д", translator.translate("d"));
	assert_eq!("е", translator.translate("e"));
	assert_eq!("ё", translator.translate("jo"));
	assert_eq!("ж", translator.translate("zh"));
	assert_eq!("з", translator.translate("z"));
	assert_eq!("и", translator.translate("i"));
	assert_eq!("й", translator.translate("j"));
	assert_eq!("к", translator.translate("k"));
	assert_eq!("л", translator.translate("l"));
	assert_eq!("м", translator.translate("m"));
	assert_eq!("н", translator.translate("n"));
	assert_eq!("о", translator.translate("o"));
	assert_eq!("п", translator.translate("p"));
	assert_eq!("р", translator.translate("r"));
	assert_eq!("с", translator.translate("s"));
	assert_eq!("т", translator.translate("t"));
	assert_eq!("у", translator.translate("u"));
	assert_eq!("ф", translator.translate("f"));
	assert_eq!("х", translator.translate("h"));
	assert_eq!("ц", translator.translate("c"));
	assert_eq!("ч", translator.translate("ch"));
	assert_eq!("ш", translator.translate("sh"));
	assert_eq!("щ", translator.translate("shh"));
	assert_eq!("ъ", translator.translate("#"));
	assert_eq!("ы", translator.translate("y"));
	assert_eq!("ь", translator.translate("'"));
	assert_eq!("э", translator.translate("je"));
	assert_eq!("ю", translator.translate("ju"));
	assert_eq!("я", translator.translate("ja"));
}

#[test]
fn capital_letters()
{
	let translator = translator::Translator::new();

	assert_eq!("А", translator.translate("A"));
	assert_eq!("Б", translator.translate("B"));
	assert_eq!("В", translator.translate("V"));
	assert_eq!("Г", translator.translate("G"));
	assert_eq!("Д", translator.translate("D"));
	assert_eq!("Е", translator.translate("E"));
	assert_eq!("Ё", translator.translate("JO"));
	assert_eq!("Ж", translator.translate("ZH"));
	assert_eq!("З", translator.translate("Z"));
	assert_eq!("И", translator.translate("I"));
	assert_eq!("Й", translator.translate("J"));
	assert_eq!("К", translator.translate("K"));
	assert_eq!("Л", translator.translate("L"));
	assert_eq!("М", translator.translate("M"));
	assert_eq!("Н", translator.translate("N"));
	assert_eq!("О", translator.translate("O"));
	assert_eq!("П", translator.translate("P"));
	assert_eq!("Р", translator.translate("R"));
	assert_eq!("С", translator.translate("S"));
	assert_eq!("Т", translator.translate("T"));
	assert_eq!("У", translator.translate("U"));
	assert_eq!("Ф", translator.translate("F"));
	assert_eq!("Х", translator.translate("X"));
	assert_eq!("Х", translator.translate("H"));
	assert_eq!("Ц", translator.translate("C"));
	assert_eq!("Ч", translator.translate("CH"));
	assert_eq!("Ш", translator.translate("SH"));
	assert_eq!("Щ", translator.translate("SHH"));
	assert_eq!("Ъ", translator.translate("##"));
	assert_eq!("Ы", translator.translate("Y"));
	assert_eq!("Ь", translator.translate("''"));
	assert_eq!("Э", translator.translate("JE"));
	assert_eq!("Ю", translator.translate("JU"));
	assert_eq!("Я", translator.translate("JA"));
}

#[test]
fn words()
{
	let translator = translator::Translator::new();

	assert_eq!("Привет", translator.translate("Privet"));
}
<|endoftext|>


<commit_before>use cxx_test_suite::extra::ffi2;
use cxx_test_suite::ffi;
use std::cell::Cell;
use std::ffi::CStr;

thread_local! {
    static CORRECT: Cell<bool> = Cell::new(false);
}

#[no_mangle]
extern "C" fn cxx_test_suite_set_correct() {
    CORRECT.with(|correct| correct.set(true));
}

macro_rules! check {
    ($run:expr) => {{
        CORRECT.with(|correct| correct.set(false));
        $run;
        assert!(CORRECT.with(|correct| correct.get()), stringify!($run));
    }};
}

#[test]
fn test_c_return() {
    let shared = ffi::Shared { z: 2020 };
    let ns_shared = ffi::AShared { z: 2020 };
    let nested_ns_shared = ffi::ABShared { z: 2020 };

    assert_eq!(2020, ffi::c_return_primitive());
    assert_eq!(2020, ffi::c_return_shared().z);
    assert_eq!(2020, *ffi::c_return_box());
    ffi::c_return_unique_ptr();
    ffi2::c_return_ns_unique_ptr();
    assert_eq!(2020, *ffi::c_return_ref(&shared));
    assert_eq!(2020, *ffi::c_return_ns_ref(&ns_shared));
    assert_eq!(2020, *ffi::c_return_nested_ns_ref(&nested_ns_shared));
    assert_eq!("2020", ffi::c_return_str(&shared));
    assert_eq!(b"2020\0", ffi::c_return_sliceu8(&shared));
    assert_eq!("2020", ffi::c_return_rust_string());
    assert_eq!("2020", ffi::c_return_unique_ptr_string().to_str().unwrap());
    assert_eq!(4, ffi::c_return_unique_ptr_vector_u8().len());
    assert_eq!(
        200_u8,
        ffi::c_return_unique_ptr_vector_u8().into_iter().sum(),
    );
    assert_eq!(
        200.5_f64,
        ffi::c_return_unique_ptr_vector_f64().into_iter().sum(),
    );
    assert_eq!(2, ffi::c_return_unique_ptr_vector_shared().len());
    assert_eq!(
        2021_usize,
        ffi::c_return_unique_ptr_vector_shared()
            .into_iter()
            .map(|o| o.z)
            .sum(),
    );
    assert_eq!(2020, ffi::c_return_identity(2020));
    assert_eq!(2021, ffi::c_return_sum(2020, 1));
    match ffi::c_return_enum(0) {
        enm @ ffi::Enum::AVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_enum(1) {
        enm @ ffi::Enum::BVal => assert_eq!(2020, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_enum(2021) {
        enm @ ffi::Enum::CVal => assert_eq!(2021, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_ns_enum(0) {
        enm @ ffi::AEnum::AAVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_nested_ns_enum(0) {
        enm @ ffi::ABEnum::ABAVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
}

#[test]
fn test_c_try_return() {
    assert_eq!((), ffi::c_try_return_void().unwrap());
    assert_eq!(2020, ffi::c_try_return_primitive().unwrap());
    assert_eq!(
        "logic error",
        ffi::c_fail_return_primitive().unwrap_err().what(),
    );
    assert_eq!(2020, *ffi::c_try_return_box().unwrap());
    assert_eq!("2020", *ffi::c_try_return_ref(&"2020".to_owned()).unwrap());
    assert_eq!("2020", ffi::c_try_return_str("2020").unwrap());
    assert_eq!(b"2020", ffi::c_try_return_sliceu8(b"2020").unwrap());
    assert_eq!("2020", ffi::c_try_return_rust_string().unwrap());
    assert_eq!("2020", &*ffi::c_try_return_unique_ptr_string().unwrap());
}

#[test]
fn test_c_take() {
    let unique_ptr = ffi::c_return_unique_ptr();
    let unique_ptr_ns = ffi2::c_return_ns_unique_ptr();

    check!(ffi::c_take_primitive(2020));
    check!(ffi::c_take_shared(ffi::Shared { z: 2020 }));
    check!(ffi::c_take_ns_shared(ffi::AShared { z: 2020 }));
    check!(ffi::ns_c_take_ns_shared(ffi::AShared { z: 2020 }));
    check!(ffi::c_take_nested_ns_shared(ffi::ABShared { z: 2020 }));
    check!(ffi::c_take_box(Box::new(2020)));
    check!(ffi::c_take_ref_c(&unique_ptr));
    check!(ffi2::c_take_ref_ns_c(&unique_ptr_ns));
    check!(cxx_test_suite::module::ffi::c_take_unique_ptr(unique_ptr));
    check!(ffi::c_take_str("2020"));
    check!(ffi::c_take_sliceu8(b"2020"));
    check!(ffi::c_take_rust_string("2020".to_owned()));
    check!(ffi::c_take_unique_ptr_string(
        ffi::c_return_unique_ptr_string()
    ));
    check!(ffi::c_take_unique_ptr_vector_u8(
        ffi::c_return_unique_ptr_vector_u8()
    ));
    check!(ffi::c_take_unique_ptr_vector_f64(
        ffi::c_return_unique_ptr_vector_f64()
    ));
    check!(ffi::c_take_unique_ptr_vector_shared(
        ffi::c_return_unique_ptr_vector_shared()
    ));
    check!(ffi::c_take_ref_vector(&ffi::c_return_unique_ptr_vector_u8()));
    let test_vec = [86_u8, 75_u8, 30_u8, 9_u8].to_vec();
    check!(ffi::c_take_rust_vec(test_vec.clone()));
    check!(ffi::c_take_rust_vec_index(test_vec.clone()));
    let shared_test_vec = vec![ffi::Shared { z: 1010 }, ffi::Shared { z: 1011 }];
    check!(ffi::c_take_rust_vec_shared(shared_test_vec.clone()));
    check!(ffi::c_take_rust_vec_shared_index(shared_test_vec.clone()));
    check!(ffi::c_take_rust_vec_shared_forward_iterator(
        shared_test_vec,
    ));
    check!(ffi::c_take_ref_rust_vec(&test_vec));
    check!(ffi::c_take_ref_rust_vec_index(&test_vec));
    check!(ffi::c_take_ref_rust_vec_copy(&test_vec));
    check!(ffi::c_take_ref_shared_string(&ffi::SharedString {
        msg: "2020".to_owned()
    }));
    let ns_shared_test_vec = vec![ffi::AShared { z: 1010 }, ffi::AShared { z: 1011 }];
    check!(ffi::c_take_rust_vec_ns_shared(ns_shared_test_vec));
    let nested_ns_shared_test_vec = vec![ffi::ABShared { z: 1010 }, ffi::ABShared { z: 1011 }];
    check!(ffi::c_take_rust_vec_nested_ns_shared(
        nested_ns_shared_test_vec
    ));

    check!(ffi::c_take_enum(ffi::Enum::AVal));
    check!(ffi::c_take_ns_enum(ffi::AEnum::AAVal));
    check!(ffi::c_take_nested_ns_enum(ffi::ABEnum::ABAVal));
}

#[test]
fn test_c_callback() {
    fn callback(s: String) -> usize {
        if s == "2020" {
            cxx_test_suite_set_correct();
        }
        0
    }

    check!(ffi::c_take_callback(callback));
}

#[test]
fn test_c_call_r() {
    fn cxx_run_test() {
        extern "C" {
            fn cxx_run_test() -> *const i8;
        }
        let failure = unsafe { cxx_run_test() };
        if !failure.is_null() {
            let msg = unsafe { CStr::from_ptr(failure as *mut std::os::raw::c_char) };
            eprintln!("{}", msg.to_string_lossy());
        }
    }
    check!(cxx_run_test());
}

#[test]
fn test_c_method_calls() {
    let mut unique_ptr = ffi::c_return_unique_ptr();

    let old_value = unique_ptr.get();
    assert_eq!(2020, old_value);
    assert_eq!(2021, unique_ptr.set(2021));
    assert_eq!(2021, unique_ptr.get());
    assert_eq!(old_value, unique_ptr.set2(old_value));
    assert_eq!(old_value, unique_ptr.get2());
    assert_eq!(2022, unique_ptr.set_succeed(2022).unwrap());
    assert!(unique_ptr.get_fail().is_err());
}

#[test]
fn test_c_ns_method_calls() {
    let unique_ptr = ffi2::ns_c_return_unique_ptr_ns();

    let old_value = unique_ptr.get();
    assert_eq!(1000, old_value);
}

#[test]
fn test_enum_representations() {
    assert_eq!(0, ffi::Enum::AVal.repr);
    assert_eq!(2020, ffi::Enum::BVal.repr);
    assert_eq!(2021, ffi::Enum::CVal.repr);
}

#[no_mangle]
extern "C" fn cxx_test_suite_get_box() -> *mut cxx_test_suite::R {
    Box::into_raw(Box::new(2020usize))
}

#[no_mangle]
unsafe extern "C" fn cxx_test_suite_r_is_correct(r: *const cxx_test_suite::R) -> bool {
    *r == 2020
}

#[test]
fn test_rust_name_attribute() {
    assert_eq!("2020", ffi::i32_overloaded_function(2020));
    assert_eq!("2020", ffi::str_overloaded_function("2020"));
    let unique_ptr = ffi::c_return_unique_ptr();
    assert_eq!("2020", unique_ptr.i32_overloaded_method(2020));
    assert_eq!("2020", unique_ptr.str_overloaded_method("2020"));
}

#[test]
fn test_extern_trivial() {
    let d = ffi2::c_return_trivial();
    check!(ffi2::c_take_trivial_ref(&d));
    check!(ffi2::c_take_trivial(d));
    let d = ffi2::c_return_trivial_ptr();
    check!(ffi2::c_take_trivial_ptr(d));
    cxx::UniquePtr::new(ffi2::D { d: 42 });
    let d = ffi2::ns_c_return_trivial();
    check!(ffi2::ns_c_take_trivial(d));

    let g = ffi2::c_return_trivial_ns();
    check!(ffi2::c_take_trivial_ns_ref(&g));
    check!(ffi2::c_take_trivial_ns(g));
    let g = ffi2::c_return_trivial_ns_ptr();
    check!(ffi2::c_take_trivial_ns_ptr(g));
    cxx::UniquePtr::new(ffi2::G { g: 42 });
}

#[test]
fn test_extern_opaque() {
    let e = ffi2::c_return_opaque_ptr();
    check!(ffi2::c_take_opaque_ref(e.as_ref().unwrap()));
    check!(ffi2::c_take_opaque_ptr(e));

    let f = ffi2::c_return_ns_opaque_ptr();
    check!(ffi2::c_take_opaque_ns_ref(f.as_ref().unwrap()));
    check!(ffi2::c_take_opaque_ns_ptr(f));
}
<commit_msg>Ignore some clippy lints in test suite<commit_after>#![allow(clippy::assertions_on_constants, clippy::float_cmp, clippy::unit_cmp)]

use cxx_test_suite::extra::ffi2;
use cxx_test_suite::ffi;
use std::cell::Cell;
use std::ffi::CStr;

thread_local! {
    static CORRECT: Cell<bool> = Cell::new(false);
}

#[no_mangle]
extern "C" fn cxx_test_suite_set_correct() {
    CORRECT.with(|correct| correct.set(true));
}

macro_rules! check {
    ($run:expr) => {{
        CORRECT.with(|correct| correct.set(false));
        $run;
        assert!(CORRECT.with(|correct| correct.get()), stringify!($run));
    }};
}

#[test]
fn test_c_return() {
    let shared = ffi::Shared { z: 2020 };
    let ns_shared = ffi::AShared { z: 2020 };
    let nested_ns_shared = ffi::ABShared { z: 2020 };

    assert_eq!(2020, ffi::c_return_primitive());
    assert_eq!(2020, ffi::c_return_shared().z);
    assert_eq!(2020, *ffi::c_return_box());
    ffi::c_return_unique_ptr();
    ffi2::c_return_ns_unique_ptr();
    assert_eq!(2020, *ffi::c_return_ref(&shared));
    assert_eq!(2020, *ffi::c_return_ns_ref(&ns_shared));
    assert_eq!(2020, *ffi::c_return_nested_ns_ref(&nested_ns_shared));
    assert_eq!("2020", ffi::c_return_str(&shared));
    assert_eq!(b"2020\0", ffi::c_return_sliceu8(&shared));
    assert_eq!("2020", ffi::c_return_rust_string());
    assert_eq!("2020", ffi::c_return_unique_ptr_string().to_str().unwrap());
    assert_eq!(4, ffi::c_return_unique_ptr_vector_u8().len());
    assert_eq!(
        200_u8,
        ffi::c_return_unique_ptr_vector_u8().into_iter().sum(),
    );
    assert_eq!(
        200.5_f64,
        ffi::c_return_unique_ptr_vector_f64().into_iter().sum(),
    );
    assert_eq!(2, ffi::c_return_unique_ptr_vector_shared().len());
    assert_eq!(
        2021_usize,
        ffi::c_return_unique_ptr_vector_shared()
            .into_iter()
            .map(|o| o.z)
            .sum(),
    );
    assert_eq!(2020, ffi::c_return_identity(2020));
    assert_eq!(2021, ffi::c_return_sum(2020, 1));
    match ffi::c_return_enum(0) {
        enm @ ffi::Enum::AVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_enum(1) {
        enm @ ffi::Enum::BVal => assert_eq!(2020, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_enum(2021) {
        enm @ ffi::Enum::CVal => assert_eq!(2021, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_ns_enum(0) {
        enm @ ffi::AEnum::AAVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
    match ffi::c_return_nested_ns_enum(0) {
        enm @ ffi::ABEnum::ABAVal => assert_eq!(0, enm.repr),
        _ => assert!(false),
    }
}

#[test]
fn test_c_try_return() {
    assert_eq!((), ffi::c_try_return_void().unwrap());
    assert_eq!(2020, ffi::c_try_return_primitive().unwrap());
    assert_eq!(
        "logic error",
        ffi::c_fail_return_primitive().unwrap_err().what(),
    );
    assert_eq!(2020, *ffi::c_try_return_box().unwrap());
    assert_eq!("2020", *ffi::c_try_return_ref(&"2020".to_owned()).unwrap());
    assert_eq!("2020", ffi::c_try_return_str("2020").unwrap());
    assert_eq!(b"2020", ffi::c_try_return_sliceu8(b"2020").unwrap());
    assert_eq!("2020", ffi::c_try_return_rust_string().unwrap());
    assert_eq!("2020", &*ffi::c_try_return_unique_ptr_string().unwrap());
}

#[test]
fn test_c_take() {
    let unique_ptr = ffi::c_return_unique_ptr();
    let unique_ptr_ns = ffi2::c_return_ns_unique_ptr();

    check!(ffi::c_take_primitive(2020));
    check!(ffi::c_take_shared(ffi::Shared { z: 2020 }));
    check!(ffi::c_take_ns_shared(ffi::AShared { z: 2020 }));
    check!(ffi::ns_c_take_ns_shared(ffi::AShared { z: 2020 }));
    check!(ffi::c_take_nested_ns_shared(ffi::ABShared { z: 2020 }));
    check!(ffi::c_take_box(Box::new(2020)));
    check!(ffi::c_take_ref_c(&unique_ptr));
    check!(ffi2::c_take_ref_ns_c(&unique_ptr_ns));
    check!(cxx_test_suite::module::ffi::c_take_unique_ptr(unique_ptr));
    check!(ffi::c_take_str("2020"));
    check!(ffi::c_take_sliceu8(b"2020"));
    check!(ffi::c_take_rust_string("2020".to_owned()));
    check!(ffi::c_take_unique_ptr_string(
        ffi::c_return_unique_ptr_string()
    ));
    check!(ffi::c_take_unique_ptr_vector_u8(
        ffi::c_return_unique_ptr_vector_u8()
    ));
    check!(ffi::c_take_unique_ptr_vector_f64(
        ffi::c_return_unique_ptr_vector_f64()
    ));
    check!(ffi::c_take_unique_ptr_vector_shared(
        ffi::c_return_unique_ptr_vector_shared()
    ));
    check!(ffi::c_take_ref_vector(&ffi::c_return_unique_ptr_vector_u8()));
    let test_vec = [86_u8, 75_u8, 30_u8, 9_u8].to_vec();
    check!(ffi::c_take_rust_vec(test_vec.clone()));
    check!(ffi::c_take_rust_vec_index(test_vec.clone()));
    let shared_test_vec = vec![ffi::Shared { z: 1010 }, ffi::Shared { z: 1011 }];
    check!(ffi::c_take_rust_vec_shared(shared_test_vec.clone()));
    check!(ffi::c_take_rust_vec_shared_index(shared_test_vec.clone()));
    check!(ffi::c_take_rust_vec_shared_forward_iterator(
        shared_test_vec,
    ));
    check!(ffi::c_take_ref_rust_vec(&test_vec));
    check!(ffi::c_take_ref_rust_vec_index(&test_vec));
    check!(ffi::c_take_ref_rust_vec_copy(&test_vec));
    check!(ffi::c_take_ref_shared_string(&ffi::SharedString {
        msg: "2020".to_owned()
    }));
    let ns_shared_test_vec = vec![ffi::AShared { z: 1010 }, ffi::AShared { z: 1011 }];
    check!(ffi::c_take_rust_vec_ns_shared(ns_shared_test_vec));
    let nested_ns_shared_test_vec = vec![ffi::ABShared { z: 1010 }, ffi::ABShared { z: 1011 }];
    check!(ffi::c_take_rust_vec_nested_ns_shared(
        nested_ns_shared_test_vec
    ));

    check!(ffi::c_take_enum(ffi::Enum::AVal));
    check!(ffi::c_take_ns_enum(ffi::AEnum::AAVal));
    check!(ffi::c_take_nested_ns_enum(ffi::ABEnum::ABAVal));
}

#[test]
fn test_c_callback() {
    fn callback(s: String) -> usize {
        if s == "2020" {
            cxx_test_suite_set_correct();
        }
        0
    }

    check!(ffi::c_take_callback(callback));
}

#[test]
fn test_c_call_r() {
    fn cxx_run_test() {
        extern "C" {
            fn cxx_run_test() -> *const i8;
        }
        let failure = unsafe { cxx_run_test() };
        if !failure.is_null() {
            let msg = unsafe { CStr::from_ptr(failure as *mut std::os::raw::c_char) };
            eprintln!("{}", msg.to_string_lossy());
        }
    }
    check!(cxx_run_test());
}

#[test]
fn test_c_method_calls() {
    let mut unique_ptr = ffi::c_return_unique_ptr();

    let old_value = unique_ptr.get();
    assert_eq!(2020, old_value);
    assert_eq!(2021, unique_ptr.set(2021));
    assert_eq!(2021, unique_ptr.get());
    assert_eq!(old_value, unique_ptr.set2(old_value));
    assert_eq!(old_value, unique_ptr.get2());
    assert_eq!(2022, unique_ptr.set_succeed(2022).unwrap());
    assert!(unique_ptr.get_fail().is_err());
}

#[test]
fn test_c_ns_method_calls() {
    let unique_ptr = ffi2::ns_c_return_unique_ptr_ns();

    let old_value = unique_ptr.get();
    assert_eq!(1000, old_value);
}

#[test]
fn test_enum_representations() {
    assert_eq!(0, ffi::Enum::AVal.repr);
    assert_eq!(2020, ffi::Enum::BVal.repr);
    assert_eq!(2021, ffi::Enum::CVal.repr);
}

#[no_mangle]
extern "C" fn cxx_test_suite_get_box() -> *mut cxx_test_suite::R {
    Box::into_raw(Box::new(2020usize))
}

#[no_mangle]
unsafe extern "C" fn cxx_test_suite_r_is_correct(r: *const cxx_test_suite::R) -> bool {
    *r == 2020
}

#[test]
fn test_rust_name_attribute() {
    assert_eq!("2020", ffi::i32_overloaded_function(2020));
    assert_eq!("2020", ffi::str_overloaded_function("2020"));
    let unique_ptr = ffi::c_return_unique_ptr();
    assert_eq!("2020", unique_ptr.i32_overloaded_method(2020));
    assert_eq!("2020", unique_ptr.str_overloaded_method("2020"));
}

#[test]
fn test_extern_trivial() {
    let d = ffi2::c_return_trivial();
    check!(ffi2::c_take_trivial_ref(&d));
    check!(ffi2::c_take_trivial(d));
    let d = ffi2::c_return_trivial_ptr();
    check!(ffi2::c_take_trivial_ptr(d));
    cxx::UniquePtr::new(ffi2::D { d: 42 });
    let d = ffi2::ns_c_return_trivial();
    check!(ffi2::ns_c_take_trivial(d));

    let g = ffi2::c_return_trivial_ns();
    check!(ffi2::c_take_trivial_ns_ref(&g));
    check!(ffi2::c_take_trivial_ns(g));
    let g = ffi2::c_return_trivial_ns_ptr();
    check!(ffi2::c_take_trivial_ns_ptr(g));
    cxx::UniquePtr::new(ffi2::G { g: 42 });
}

#[test]
fn test_extern_opaque() {
    let e = ffi2::c_return_opaque_ptr();
    check!(ffi2::c_take_opaque_ref(e.as_ref().unwrap()));
    check!(ffi2::c_take_opaque_ptr(e));

    let f = ffi2::c_return_ns_opaque_ptr();
    check!(ffi2::c_take_opaque_ns_ref(f.as_ref().unwrap()));
    check!(ffi2::c_take_opaque_ns_ptr(f));
}
<|endoftext|>


<commit_before>#![feature(collections)]

extern crate mio;
extern crate hyperhyper;

use std::rc::Rc;
use hyperhyper::poke_web_page;
use hyperhyper::HttpAction;

#[test]
fn get_a_simple_webpage() {
    poke_web_page("news.ycombinator.com".to_string(),
    	80,
    	HttpAction::Get(Rc::new(String::from_str("/"))));
}
<commit_msg>added some basic tests<commit_after>#![feature(collections)]

extern crate mio;
extern crate hyperhyper;

use std::rc::Rc;
use hyperhyper::poke_web_page;
use hyperhyper::HttpAction;

#[test]
fn get_a_simple_webpage() {
    let result:Vec<u8> = poke_web_page("google.com".to_string(),
    	80,
    	HttpAction::Get(Rc::new(String::from_str("/"))));
	assert!(String::from_utf8(result).unwrap().contains("google"));
}
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animatable=False)}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
${helpers.single_keyword("list-style-type", """
    disc none circle square decimal lower-alpha upper-alpha  disclosure-open disclosure-closed
""", extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari
                           gujarati gurmukhi kannada khmer lao malayalam mongolian
                           myanmar oriya persian telugu thai tibetan cjk-earthly-branch
                           cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana
                           katakana-iroha""",
    gecko_constant_prefix="NS_STYLE_LIST_STYLE",
    animatable=False)}

${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_)",
                          animatable="False")}

<%helpers:longhand name="quotes" animatable="False">
    use cssparser::Token;
    use std::borrow::Cow;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::NoViewportPercentage;

    pub use self::computed_value::T as SpecifiedValue;

    pub mod computed_value {
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T(pub Vec<(String,String)>);
    }

    impl ComputedValueAsSpecified for SpecifiedValue {}
    impl NoViewportPercentage for SpecifiedValue {}

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut first = true;
            for pair in &self.0 {
                if !first {
                    try!(dest.write_str(" "));
                }
                first = false;
                try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest));
                try!(dest.write_str(" "));
                try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest));
            }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(vec![
            ("\u{201c}".to_owned(), "\u{201d}".to_owned()),
            ("\u{2018}".to_owned(), "\u{2019}".to_owned()),
        ])
    }

    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(SpecifiedValue(Vec::new()))
        }

        let mut quotes = Vec::new();
        loop {
            let first = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                Ok(_) => return Err(()),
                Err(()) => break,
            };
            let second = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                _ => return Err(()),
            };
            quotes.push((first, second))
        }
        if !quotes.is_empty() {
            Ok(SpecifiedValue(quotes))
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<commit_msg>Auto merge of #14645 - upsuper:gecko-builtin-counter-styles, r=heycam<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("List", inherited=True) %>

${helpers.single_keyword("list-style-position", "outside inside", animatable=False)}

// TODO(pcwalton): Implement the full set of counter styles per CSS-COUNTER-STYLES [1] 6.1:
//
//     decimal-leading-zero, armenian, upper-armenian, lower-armenian, georgian, lower-roman,
//     upper-roman
//
// TODO(bholley): Missing quite a few gecko properties here as well.
//
// [1]: http://dev.w3.org/csswg/css-counter-styles/
${helpers.single_keyword("list-style-type", """
    disc none circle square decimal disclosure-open disclosure-closed
""", extra_servo_values="""arabic-indic bengali cambodian cjk-decimal devanagari
                           gujarati gurmukhi kannada khmer lao malayalam mongolian
                           myanmar oriya persian telugu thai tibetan cjk-earthly-branch
                           cjk-heavenly-stem lower-greek hiragana hiragana-iroha katakana
                           katakana-iroha lower-alpha upper-alpha""",
    gecko_constant_prefix="NS_STYLE_LIST_STYLE",
    animatable=False)}

${helpers.predefined_type("list-style-image", "UrlOrNone", "Either::Second(None_)",
                          animatable="False")}

<%helpers:longhand name="quotes" animatable="False">
    use cssparser::Token;
    use std::borrow::Cow;
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::NoViewportPercentage;

    pub use self::computed_value::T as SpecifiedValue;

    pub mod computed_value {
        #[derive(Debug, Clone, PartialEq)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub struct T(pub Vec<(String,String)>);
    }

    impl ComputedValueAsSpecified for SpecifiedValue {}
    impl NoViewportPercentage for SpecifiedValue {}

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            let mut first = true;
            for pair in &self.0 {
                if !first {
                    try!(dest.write_str(" "));
                }
                first = false;
                try!(Token::QuotedString(Cow::from(&*pair.0)).to_css(dest));
                try!(dest.write_str(" "));
                try!(Token::QuotedString(Cow::from(&*pair.1)).to_css(dest));
            }
            Ok(())
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T(vec![
            ("\u{201c}".to_owned(), "\u{201d}".to_owned()),
            ("\u{2018}".to_owned(), "\u{2019}".to_owned()),
        ])
    }

    pub fn parse(_: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
        if input.try(|input| input.expect_ident_matching("none")).is_ok() {
            return Ok(SpecifiedValue(Vec::new()))
        }

        let mut quotes = Vec::new();
        loop {
            let first = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                Ok(_) => return Err(()),
                Err(()) => break,
            };
            let second = match input.next() {
                Ok(Token::QuotedString(value)) => value.into_owned(),
                _ => return Err(()),
            };
            quotes.push((first, second))
        }
        if !quotes.is_empty() {
            Ok(SpecifiedValue(quotes))
        } else {
            Err(())
        }
    }
</%helpers:longhand>
<|endoftext|>


<commit_before>use git::Config;
use author::Author;
use error::PartnersError;
use Result;

pub struct AuthorSelection<'a> {
    config: &'a Config<'a>,
    authors: Vec<Author>,
}

impl<'a> AuthorSelection<'a> {
    pub fn new(config: &'a Config<'a>, authors: Vec<Author>) -> Result<AuthorSelection<'a>> {
        if authors.len() == 0 {
            Err(PartnersError::NoAuthorSpecified)
        } else {
            Ok(AuthorSelection { config: config, authors: authors })
        }
    }

    pub fn name(&self) -> String {
        if self.authors.len() == 1 {
            self.authors[0].name.to_string()
        } else {
            self.authors.iter().map(|a| a.name.to_string()).collect::<Vec<_>>().join(", ")
        }
    }

    pub fn nick(&self) -> String {
        if self.authors.len() == 1 {
            self.authors[0].nick.to_string()
        } else {
            self.authors.iter().map(|a| a.nick.to_string()).collect::<Vec<_>>().join(&self.config.separator())
        }
    }

    pub fn email(&self) -> String {
        if self.authors.len() == 1 {
            if let Some(ref email) = self.authors[0].email.as_ref() {
                email.to_string()
            } else {
                format!("{}@{}", self.nick(), self.config.domain())
            }
        } else {
            format!("{}{}{}@{}", self.config.prefix(), self.config.separator(), self.nick(), self.config.domain())
        }
    }
}<commit_msg>Make author selection sorted<commit_after>use git::Config;
use author::Author;
use error::PartnersError;
use Result;

pub struct AuthorSelection<'a> {
    config: &'a Config<'a>,
    authors: Vec<Author>,
}

impl<'a> AuthorSelection<'a> {
    pub fn new(config: &'a Config<'a>, mut authors: Vec<Author>) -> Result<AuthorSelection<'a>> {
        if authors.len() == 0 {
            Err(PartnersError::NoAuthorSpecified)
        } else {
            authors.sort();
            Ok(AuthorSelection { config: config, authors: authors })
        }
    }

    pub fn name(&self) -> String {
        if self.authors.len() == 1 {
            self.authors[0].name.to_string()
        } else {
            self.authors.iter().map(|a| a.name.to_string()).collect::<Vec<_>>().join(", ")
        }
    }

    pub fn nick(&self) -> String {
        if self.authors.len() == 1 {
            self.authors[0].nick.to_string()
        } else {
            self.authors.iter().map(|a| a.nick.to_string()).collect::<Vec<_>>().join(&self.config.separator())
        }
    }

    pub fn email(&self) -> String {
        if self.authors.len() == 1 {
            if let Some(ref email) = self.authors[0].email.as_ref() {
                email.to_string()
            } else {
                format!("{}@{}", self.nick(), self.config.domain())
            }
        } else {
            format!("{}{}{}@{}", self.config.prefix(), self.config.separator(), self.nick(), self.config.domain())
        }
    }
}<|endoftext|>


<commit_before>//! TODO Fill in

use super::class::{self, Class};
use super::object::{self, Object, Objectable};
use super::property::Property;
use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, AnyUserData, LightUserData, Lua, Table, ToLua, UserData, UserDataMethods, Value};
use std::default::Default;
use std::fmt::{self, Display, Formatter};
use wlroots::{Area, Origin, Size};

#[derive(Clone, Debug)]
pub struct DrawableState {
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub struct Drawable<'lua>(Object<'lua>);

impl_objectable!(Drawable, DrawableState);

impl Default for DrawableState {
    fn default() -> Self {
        DrawableState { surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref surface) => {
                let stash = surface.to_glib_none();
                let ptr = stash.0 as _;
                Value::LightUserData(LightUserData(ptr))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.get_object_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.surface = None;
            drawable.refreshed = false;
            let size: Size = geometry.size;
            if size.width > 0 && size.height > 0 {
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                        size.width,
                                                        size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                // TODO emity property::surface
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.get_object_mut()?;
        drawable.refreshed = true;
        Ok(())
    }
}

impl Display for DrawableState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawable: {:p}", self)
    }
}

impl<'lua> ToLua<'lua> for Drawable<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<Value<'lua>> {
    let drawable = Drawable::cast(obj.into())?;
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let drawable = Drawable::cast(obj.into())?;
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<()> {
    Drawable::cast(obj.into())?.refresh()
}
<commit_msg>Fixed abort on shutdown<commit_after>//! TODO Fill in

use super::class::{self, Class};
use super::object::{self, Object, Objectable};
use super::property::Property;
use cairo::{Format, ImageSurface};
use glib::translate::ToGlibPtr;
use rlua::{self, AnyUserData, LightUserData, Lua, Table, ToLua, UserData, UserDataMethods, Value};
use std::default::Default;
use std::fmt::{self, Display, Formatter};
use wlroots::{Area, Origin, Size};

#[derive(Clone, Debug)]
pub struct DrawableState {
    pub surface: Option<ImageSurface>,
    geo: Area,
    // TODO Use this to determine whether we draw this or not
    refreshed: bool
}

pub struct Drawable<'lua>(Object<'lua>);

impl_objectable!(Drawable, DrawableState);

impl Default for DrawableState {
    fn default() -> Self {
        DrawableState { surface: None,
                        geo: Area::default(),
                        refreshed: false }
    }
}

impl<'lua> Drawable<'lua> {
    pub fn new(lua: &Lua) -> rlua::Result<Object> {
        let class = class::class_setup(lua, "drawable")?;
        let builder = Drawable::allocate(lua, class)?;
        // TODO Do properly
        let table = lua.create_table()?;
        table.set("geometry", lua.create_function(geometry)?)?;
        table.set("refresh", lua.create_function(refresh)?)?;
        Ok(builder.add_to_meta(table)?.build())
    }

    pub fn get_geometry(&self) -> rlua::Result<Area> {
        let drawable = self.state()?;
        Ok(drawable.geo)
    }

    pub fn get_surface(&self) -> rlua::Result<Value<'lua>> {
        let drawable = self.state()?;
        Ok(match drawable.surface {
            None => Value::Nil,
            Some(ref surface) => {
                let stash = surface.to_glib_none();
                let ptr = stash.0;
                // NOTE
                // We bump the reference count because now Lua has a reference which
                // it manages via LGI.
                //
                // If there's a bug, worst case scenario there's a memory leak.
                unsafe {
                    ::cairo_sys::cairo_surface_reference(ptr);
                }
                Value::LightUserData(LightUserData(ptr as _))
            }
        })
    }

    /// Sets the geometry, and allocates a new surface.
    pub fn set_geometry(&mut self, geometry: Area) -> rlua::Result<()> {
        use rlua::Error::RuntimeError;
        let mut drawable = self.get_object_mut()?;
        let size_changed = drawable.geo != geometry;
        drawable.geo = geometry;
        if size_changed {
            drawable.surface = None;
            drawable.refreshed = false;
            let size: Size = geometry.size;
            if size.width > 0 && size.height > 0 {
                drawable.surface = Some(ImageSurface::create(Format::ARgb32,
                                                        size.width,
                                                        size.height)
                    .map_err(|err| RuntimeError(format!("Could not allocate {:?}", err)))?);
                // TODO emity property::surface
            }
        }
        Ok(())
    }

    /// Signals that the drawable's surface was updated.
    pub fn refresh(&mut self) -> rlua::Result<()> {
        let mut drawable = self.get_object_mut()?;
        drawable.refreshed = true;
        Ok(())
    }
}

impl Display for DrawableState {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "Drawable: {:p}", self)
    }
}

impl<'lua> ToLua<'lua> for Drawable<'lua> {
    fn to_lua(self, lua: &'lua Lua) -> rlua::Result<Value<'lua>> {
        self.0.to_lua(lua)
    }
}

impl UserData for DrawableState {
    fn add_methods(methods: &mut UserDataMethods<Self>) {
        object::default_add_methods(methods);
    }
}

pub fn init(lua: &Lua) -> rlua::Result<Class> {
    Class::builder(lua, "drawable", None)?
        .method("geometry".into(), lua.create_function(geometry)?)?
        .property(Property::new("surface".into(),
                                None,
                                Some(lua.create_function(get_surface)?),
                                None))?
        .save_class("drawable")?
        .build()
}

fn get_surface<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<Value<'lua>> {
    let drawable = Drawable::cast(obj.into())?;
    drawable.get_surface()
}

fn geometry<'lua>(lua: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<Table<'lua>> {
    let drawable = Drawable::cast(obj.into())?;
    let geometry = drawable.get_geometry()?;
    let Origin { x, y } = geometry.origin;
    let Size { width, height } = geometry.size;
    let table = lua.create_table()?;
    table.set("x", x)?;
    table.set("y", y)?;
    table.set("width", width)?;
    table.set("height", height)?;
    Ok(table)
}

fn refresh<'lua>(_: &'lua Lua, obj: AnyUserData<'lua>) -> rlua::Result<()> {
    Drawable::cast(obj.into())?.refresh()
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
    notification::{Notification, ShowMessage},
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
    InitializationOptions,
};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(
                    roots,
                    InitializationOptions::default(),
                    &mut msg_receiver,
                    &mut msg_sender,
                )
                .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        match find_mismatch(&expected_resp, &actual) {
            Some((expected_part, actual_part)) => panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            ),
            None => {}
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(50);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<commit_msg>bump timeout for CI<commit_after>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
    notification::{Notification, ShowMessage},
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
    InitializationOptions,
};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(
                    roots,
                    InitializationOptions::default(),
                    &mut msg_receiver,
                    &mut msg_sender,
                )
                .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        match find_mismatch(&expected_resp, &actual) {
            Some((expected_part, actual_part)) => panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            ),
            None => {}
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<|endoftext|>