<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 rust_name_attr: Vec<_> = match &analysis.rust_rename_strategy {
        RustRenameStrategy::RenameUsingRustAttr => Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap(),
        _ => Vec::new(),
    };
    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 = any_param_needs_rust_conversion
        || (cxxbridge_name != rust_name && matches!(kind, FnKind::Method(..)))
        || matches!(kind, FnKind::TraitMethod { .. });
    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)*
        #(#rust_name_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>Slight tidy.<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 rust_name_attr: Vec<_> = match &analysis.rust_rename_strategy {
        RustRenameStrategy::RenameUsingRustAttr => Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap(),
        _ => Vec::new(),
    };
    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,
        _ => 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)*
        #(#rust_name_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()
    }
}
<|endoftext|>


<commit_before>use super::arch::RVA;

const PAGE_SIZE: usize = 0x1000;

#[derive(Debug)]
pub enum Error {
    NotMapped,
}

fn page(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) >> 12
}

fn page_offset(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) & 0xFFF
}

pub struct Page<T: Default + Copy> {
    pub elements: [T; PAGE_SIZE],
}

impl<T: Default + Copy> Page<T> {
    pub fn new(items: &[T]) -> Page<T> {
        let mut page: Page<T> = Default::default();
        page.elements.copy_from_slice(items);
        page
    }
}

impl<T: Default + Copy> Default for Page<T> {
    fn default() -> Self {
        Page {
            elements: [Default::default(); PAGE_SIZE]
        }
    }
}

pub struct DenseAddressSpace<T: Default + Copy> {
    pages: Vec<Option<Page<T>>>
}

impl<T: Default + Copy> DenseAddressSpace<T> {
    pub fn with_capacity(capacity: RVA) -> DenseAddressSpace<T>{
        let page_count = page(capacity) + 1;
        let mut pages = Vec::with_capacity(page_count);
        pages.resize_with(page_count, || None);

        DenseAddressSpace {
            pages
        }
    }

    /// error if rva is not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be PAGE_SIZE number of items.
    fn map_page(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        if page_offset(rva) != 0 {
            panic!("invalid map address");
        }
        if items.len() != PAGE_SIZE {
            panic!("invalid map buffer size");
        }
        if page(rva) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        self.pages[page(rva)] = Some(Page::new(items));

        Ok(())
    }

    /// map the given items at the given address.
    ///
    /// error if rva or items are not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be multiple of PAGE_SIZE number of items.
    ///
    /// see example under `get`.
    pub fn map(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        for (i, chunk) in items.chunks_exact(PAGE_SIZE).enumerate() {
            self.map_page(rva + i * PAGE_SIZE, chunk)?
        }
        Ok(())
    }

    /// map the default value (probably zero) at the given address for the given size.
    ///
    /// same error conditions as `map`.
    /// see example under `probe`.
    pub fn map_empty(&mut self, rva: RVA, size: usize) -> Result<(), Error> {
        self.map(rva, &vec![Default::default(); size])
    }

    /// is the given address mapped?
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// assert_eq!(d.probe(0x0.into()), false);
    /// assert_eq!(d.probe(0x1000.into()), false);
    ///
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.probe(0x0.into()), true);
    /// assert_eq!(d.probe(0x1000.into()), false);
    /// ```
    pub fn probe(&self, rva: RVA) -> bool {
        if page(rva) > self.pages.len() {
            return false;
        }

        return self.pages[page(rva)].is_some()
    }

    /// fetch one item from the given address.
    /// if the address is not mapped, then the result is `None`.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), None);
    ///
    /// d.map(0x1000.into(), &[0x1; 0x1000]).expect("failed to map");
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), Some(0x1));
    ///
    /// d.map(0x0.into(), &[0x2; 0x2000]).expect("failed to map");
    ///  assert_eq!(d.get(0x0.into()), Some(0x2));
    ///  assert_eq!(d.get(0x1000.into()), Some(0x2));
    /// ```
    pub fn get(&self, rva: RVA) -> Option<T> {
        if page(rva) > self.pages.len() {
            return None;
        }

        let page = match &self.pages[page(rva)] {
            // page is not mapped
            None => return None,
            // page is mapped
            Some(page) => page,
        };

        Some(page.elements[page_offset(rva)])

    }

    /// handle the simple slice case: when start and end fall within the same page.
    /// for example, reading a dword from address 0x10.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.slice(0x0.into(), 0x2.into()).unwrap(), [0x0, 0x0]);
    /// ```
    fn slice_simple(&self, start: RVA, end: RVA) -> Result<&[T], Error> {
        if page(start) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        let page = match &self.pages[page(start)] {
            // page is not mapped
            None => return Err(Error::NotMapped),
            // page is mapped
            Some(page) => page,
        };

        Ok(&page.elements[page_offset(start)..page_offset(end)])
    }

    fn slice_split(&self, start: RVA, end: RVA) -> Result<&[T], Error> {
        // TODO
        self.slice_simple(start, end)
    }

    /// fetch the items found in the given range.
    ///
    /// errors:
    ///   - Error::NotMapped: if any requested address is not mapped
    ///
    /// panic if:
    ///   - start > end
    pub fn slice(&self, start: RVA, end: RVA) -> Result<&[T], Error> {
        if start > end {
            panic!("start > end");
        }

        if page(start) == page(end) {
            self.slice_simple(start, end)
        } else {
            self.slice_split(start, end)
        }
    }
}
<commit_msg>aspace: implement slice_split<commit_after>use log::{debug};

use super::arch::RVA;

const PAGE_SIZE: usize = 0x1000;

#[derive(Debug)]
pub enum Error {
    NotMapped,
}

fn page(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) >> 12
}

fn page_offset(rva: RVA) -> usize {
    // depends on PAGE_SIZE
    let v: u64 = rva.into();
    // #yolo
    (v as usize) & 0xFFF
}

pub struct Page<T: Default + Copy> {
    pub elements: [T; PAGE_SIZE],
}

impl<T: Default + Copy> Page<T> {
    pub fn new(items: &[T]) -> Page<T> {
        let mut page: Page<T> = Default::default();
        page.elements.copy_from_slice(items);
        page
    }
}

impl<T: Default + Copy> Default for Page<T> {
    fn default() -> Self {
        Page {
            elements: [Default::default(); PAGE_SIZE]
        }
    }
}

pub struct DenseAddressSpace<T: Default + Copy> {
    pages: Vec<Option<Page<T>>>
}

impl<T: Default + Copy> DenseAddressSpace<T> {
    pub fn with_capacity(capacity: RVA) -> DenseAddressSpace<T>{
        let page_count = page(capacity) + 1;
        let mut pages = Vec::with_capacity(page_count);
        pages.resize_with(page_count, || None);

        DenseAddressSpace {
            pages
        }
    }

    /// error if rva is not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be PAGE_SIZE number of items.
    fn map_page(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        if page_offset(rva) != 0 {
            panic!("invalid map address");
        }
        if items.len() != PAGE_SIZE {
            panic!("invalid map buffer size");
        }
        debug!("mapping page: {}", rva);
        if page(rva) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        self.pages[page(rva)] = Some(Page::new(items));

        Ok(())
    }

    /// map the given items at the given address.
    ///
    /// error if rva or items are not in a valid page.
    /// panic due to:
    ///   - rva must be page aligned.
    ///   - must be multiple of PAGE_SIZE number of items.
    ///
    /// see example under `get`.
    pub fn map(&mut self, rva: RVA, items: &[T]) -> Result<(), Error> {
        for (i, chunk) in items.chunks_exact(PAGE_SIZE).enumerate() {
            self.map_page(rva + i * PAGE_SIZE, chunk)?;
        }
        Ok(())
    }

    /// map the default value (probably zero) at the given address for the given size.
    ///
    /// same error conditions as `map`.
    /// see example under `probe`.
    pub fn map_empty(&mut self, rva: RVA, size: usize) -> Result<(), Error> {
        self.map(rva, &vec![Default::default(); size])
    }

    /// is the given address mapped?
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// assert_eq!(d.probe(0x0.into()), false);
    /// assert_eq!(d.probe(0x1000.into()), false);
    ///
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.probe(0x0.into()), true);
    /// assert_eq!(d.probe(0x1000.into()), false);
    /// ```
    pub fn probe(&self, rva: RVA) -> bool {
        if page(rva) > self.pages.len() {
            return false;
        }

        return self.pages[page(rva)].is_some()
    }

    /// fetch one item from the given address.
    /// if the address is not mapped, then the result is `None`.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), None);
    ///
    /// d.map(0x1000.into(), &[0x1; 0x1000]).expect("failed to map");
    /// assert_eq!(d.get(0x0.into()), None);
    /// assert_eq!(d.get(0x1000.into()), Some(0x1));
    ///
    /// d.map(0x0.into(), &[0x2; 0x2000]).expect("failed to map");
    ///  assert_eq!(d.get(0x0.into()), Some(0x2));
    ///  assert_eq!(d.get(0x1000.into()), Some(0x2));
    /// ```
    pub fn get(&self, rva: RVA) -> Option<T> {
        if page(rva) > self.pages.len() {
            return None;
        }

        let page = match &self.pages[page(rva)] {
            // page is not mapped
            None => return None,
            // page is mapped
            Some(page) => page,
        };

        Some(page.elements[page_offset(rva)])

    }

    /// handle the simple slice case: when start and end fall within the same page.
    /// for example, reading a dword from address 0x10.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x2000.into());
    /// d.map_empty(0x0.into(), 0x1000).expect("failed to map");
    /// assert_eq!(d.slice(0x0.into(), 0x2.into()).unwrap(), [0x0, 0x0]);
    /// ```
    fn slice_simple(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        if page(start) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        let page = match &self.pages[page(start)] {
            // page is not mapped
            None => return Err(Error::NotMapped),
            // page is mapped
            Some(page) => page,
        };

        Ok(page.elements[page_offset(start)..page_offset(end)].to_vec())
    }

    /// handle the complex slice case: when start and end are on different pages.
    /// for example, reading a dword from address 0xFFE.
    ///
    /// ```
    /// use lancelot::arch::RVA;
    /// use lancelot::aspace::DenseAddressSpace;
    ///
    /// let mut d: DenseAddressSpace<u32> = DenseAddressSpace::with_capacity(0x5000.into());
    /// d.map_empty(0x1000.into(), 0x3000).expect("failed to map");
    ///
    /// // 0     unmapped
    /// //       unmapped
    /// // 1000  0 0 0 0
    /// //       0 0 0 0
    /// // 2000  0 0 0 0
    /// //       0 0 0 0
    /// // 3000  0 0 0 0
    /// //       0 0 0 0
    /// // 4000  unmapped
    /// //       unmapped
    /// // 5000  unmapped
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x2000.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "no overlap");
    /// assert_eq!(d.slice(0x1FFD.into(), 0x2001.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 1");
    /// assert_eq!(d.slice(0x1FFE.into(), 0x2002.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 2");
    /// assert_eq!(d.slice(0x1FFF.into(), 0x2003.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 3");
    /// assert_eq!(d.slice(0x2000.into(), 0x2004.into()).unwrap(), [0x0, 0x0, 0x0, 0x0], "overlap 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3004.into()).unwrap().len(), 0x1008, "4, page, 4");
    ///
    /// assert_eq!(d.slice(0x1FFC.into(), 0x3000.into()).unwrap().len(), 0x1004, "4, page");
    ///
    /// assert_eq!(d.slice(0x2000.into(), 0x3004.into()).unwrap().len(), 0x1004, "page, 4");
    /// ```
    fn slice_split(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        // precondition: end > start

        if page(end) > self.pages.len() {
            return Err(Error::NotMapped);
        }

        // ensure each page within the requested region is mapped.
        let start_page = page(start);
        let end_page = if page_offset(end) == 0 { page(end) - 1} else { page(end) };
        for page in start_page..end_page {
            if ! self.probe((page * PAGE_SIZE).into()) {
                return Err(Error::NotMapped);
            }
        }

        let mut ret: Vec<T> = Vec::with_capacity((end - start).into());

        // region one: from `start` to the end of its page
        // region two: any intermediate complete pages
        // region three: from start of final page until `end`

        // one.
        {
            let page = self.pages[page(start)].as_ref().unwrap();
            let buf = &page.elements[page_offset(start)..];
            ret.extend_from_slice(buf);
        }

        // two.
        if page(start) != page(end) - 1 {
            let start_index = page(start) + 1;
            let end_index = page(end);
            for page_index in start_index..end_index {
                let page = self.pages[page_index].as_ref().unwrap();
                let buf = &page.elements[..];
                ret.extend_from_slice(buf);
            }
        }

        // three.
        if page_offset(end) != 0x0 {
            let page = self.pages[page(end)].as_ref().unwrap();
            let buf = &page.elements[..page_offset(end)];
            ret.extend_from_slice(buf);
        }

        Ok(ret)
    }

    /// fetch the items found in the given range.
    ///
    /// errors:
    ///   - Error::NotMapped: if any requested address is not mapped
    ///
    /// panic if:
    ///   - start > end
    pub fn slice(&self, start: RVA, end: RVA) -> Result<Vec<T>, Error> {
        if start > end {
            panic!("start > end");
        }

        if page(start) == page(end) {
            self.slice_simple(start, end)
        } else {
            self.slice_split(start, end)
        }
    }

    // TODO: slice_into
}
<|endoftext|>


<commit_before>use anyhow::Result;
use byteorder::{ByteOrder, LittleEndian};

use crate::{
    pagemap::{PageMap, PageMapError},
    RVA, VA,
};

pub trait AddressSpace<T> {
    fn read_into(&self, offset: T, buf: &mut [u8]) -> Result<()>;

    fn read_u8(&self, offset: T) -> Result<u8> {
        let mut buf = [0u8; 1];
        self.read_into(offset, &mut buf)?;
        Ok(buf[0])
    }

    fn read_u16(&self, offset: T) -> Result<u16> {
        let mut buf = [0u8; 2];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u16(&buf))
    }

    fn read_u32(&self, offset: T) -> Result<u32> {
        let mut buf = [0u8; 4];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u32(&buf))
    }

    fn read_u64(&self, offset: T) -> Result<u64> {
        let mut buf = [0u8; 8];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u64(&buf))
    }

    // TODO: rename read_bytes
    fn read_buf(&self, offset: T, length: usize) -> Result<Vec<u8>> {
        let mut buf = vec![0u8; length];
        self.read_into(offset, &mut buf)?;
        Ok(buf)
    }

    /// Read a NULL-terminated, ASCII-encoded string at the given offset.
    ///
    /// Errors:
    ///
    ///   - PageMapError - if the address is not mapped.
    ///   - std::str::from_utf8 errors - if the data is not valid utf8
    fn read_ascii(&self, offset: T) -> Result<String>;
}

/// An AddressSpace in which data is mapped at or near after a base address,
/// and addressed using positive offsets from this base address.
///
/// For example, this is appropriate for a PE file loaded into memory, using
/// pointers relative to the preferred base address. Here, OEP might be 0x1000.
///
/// Note that this implements `AddressSpace<RVA>` and not `AddressSpace<VA>`.
/// Use `AbsoluteAddressSpace` when you're dealing with absolute addresses
/// (`VA`).
#[derive(Clone)]
pub struct RelativeAddressSpace {
    pub(crate) map: PageMap<u8>,
}

impl RelativeAddressSpace {
    pub fn into_absolute(self, base_address: VA) -> Result<AbsoluteAddressSpace> {
        Ok(AbsoluteAddressSpace {
            base_address,
            relative: self,
        })
    }

    pub fn with_capacity(size: u64) -> RelativeAddressSpace {
        RelativeAddressSpace {
            map: PageMap::with_capacity(size),
        }
    }
}

impl AddressSpace<RVA> for RelativeAddressSpace {
    fn read_into(&self, offset: RVA, buf: &mut [u8]) -> Result<()> {
        self.map.slice_into(offset, buf)?;
        Ok(())
    }

    fn read_ascii(&self, offset: RVA) -> Result<String> {
        let buf: Vec<u8> = (offset..std::u64::MAX)
            .map(|offset| self.map.get(offset))
            .take_while(|c| c.is_some())
            .map(|c| c.unwrap())
            .take_while(|&c| c != 0)
            .collect();

        Ok(String::from_utf8(buf)?)
    }
}

/// An AddressSpace in which (mostly) contiguous data is mapped at a base
/// address, is addressed using absolute pointers (relative to 0x0).
///
/// For example, this is appropriate for a PE file loaded into memory at its
/// preferred base address, using pointers relative to 0x0. Here, OEP might be
/// 0x401000.
///
/// Internally, this is a `RelativeAddressSpace` + a base address.
/// So, its not a good fit for multiple modules that may be mapped different
/// places. Probably want to implement `SparseAddressSpace` (collection of
/// `AbsoluteAddressSpace`s)  for this.
///
/// Note that this implements `AddressSpace<VA>` and not `AddressSpace<RVA>`.
/// Use `RelativeAddressSpace` when you're dealing with relative addresses
/// (`RVA`).
#[derive(Clone)]
pub struct AbsoluteAddressSpace {
    pub base_address: VA,

    /// The inner relative address space with data mapped at `base_address`.
    /// Its ok to reach into this address space if you've got RVAs relative to
    /// `base_address`.
    pub relative: RelativeAddressSpace,
}

impl AddressSpace<VA> for AbsoluteAddressSpace {
    fn read_into(&self, offset: VA, buf: &mut [u8]) -> Result<()> {
        if offset < self.base_address {
            return Err(PageMapError::NotMapped.into());
        }

        self.relative.read_into((offset - self.base_address) as RVA, buf)
    }

    fn read_ascii(&self, offset: VA) -> Result<String> {
        if offset < self.base_address {
            return Err(PageMapError::NotMapped.into());
        }

        self.relative.read_ascii((offset - self.base_address) as RVA)
    }
}
<commit_msg>aspace: add from_buf<commit_after>use anyhow::Result;
use byteorder::{ByteOrder, LittleEndian};

use crate::{
    pagemap::{PageMap, PageMapError},
    RVA, VA,
};

pub trait AddressSpace<T> {
    fn read_into(&self, offset: T, buf: &mut [u8]) -> Result<()>;

    fn read_u8(&self, offset: T) -> Result<u8> {
        let mut buf = [0u8; 1];
        self.read_into(offset, &mut buf)?;
        Ok(buf[0])
    }

    fn read_u16(&self, offset: T) -> Result<u16> {
        let mut buf = [0u8; 2];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u16(&buf))
    }

    fn read_u32(&self, offset: T) -> Result<u32> {
        let mut buf = [0u8; 4];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u32(&buf))
    }

    fn read_u64(&self, offset: T) -> Result<u64> {
        let mut buf = [0u8; 8];
        self.read_into(offset, &mut buf)?;
        Ok(LittleEndian::read_u64(&buf))
    }

    // TODO: rename read_bytes
    fn read_buf(&self, offset: T, length: usize) -> Result<Vec<u8>> {
        let mut buf = vec![0u8; length];
        self.read_into(offset, &mut buf)?;
        Ok(buf)
    }

    /// Read a NULL-terminated, ASCII-encoded string at the given offset.
    ///
    /// Errors:
    ///
    ///   - PageMapError - if the address is not mapped.
    ///   - std::str::from_utf8 errors - if the data is not valid utf8
    fn read_ascii(&self, offset: T) -> Result<String>;
}

/// An AddressSpace in which data is mapped at or near after a base address,
/// and addressed using positive offsets from this base address.
///
/// For example, this is appropriate for a PE file loaded into memory, using
/// pointers relative to the preferred base address. Here, OEP might be 0x1000.
///
/// Note that this implements `AddressSpace<RVA>` and not `AddressSpace<VA>`.
/// Use `AbsoluteAddressSpace` when you're dealing with absolute addresses
/// (`VA`).
#[derive(Clone)]
pub struct RelativeAddressSpace {
    pub(crate) map: PageMap<u8>,
}

impl RelativeAddressSpace {
    pub fn into_absolute(self, base_address: VA) -> Result<AbsoluteAddressSpace> {
        Ok(AbsoluteAddressSpace {
            base_address,
            relative: self,
        })
    }

    pub fn with_capacity(size: u64) -> RelativeAddressSpace {
        RelativeAddressSpace {
            map: PageMap::with_capacity(size),
        }
    }

    pub fn from_buf(buf: &[u8]) -> RelativeAddressSpace {
        RelativeAddressSpace {
            map: PageMap::from_items(buf),
        }
    }
}

impl AddressSpace<RVA> for RelativeAddressSpace {
    fn read_into(&self, offset: RVA, buf: &mut [u8]) -> Result<()> {
        self.map.slice_into(offset, buf)?;
        Ok(())
    }

    fn read_ascii(&self, offset: RVA) -> Result<String> {
        let buf: Vec<u8> = (offset..std::u64::MAX)
            .map(|offset| self.map.get(offset))
            .take_while(|c| c.is_some())
            .map(|c| c.unwrap())
            .take_while(|&c| c != 0)
            .collect();

        Ok(String::from_utf8(buf)?)
    }
}

/// An AddressSpace in which (mostly) contiguous data is mapped at a base
/// address, is addressed using absolute pointers (relative to 0x0).
///
/// For example, this is appropriate for a PE file loaded into memory at its
/// preferred base address, using pointers relative to 0x0. Here, OEP might be
/// 0x401000.
///
/// Internally, this is a `RelativeAddressSpace` + a base address.
/// So, its not a good fit for multiple modules that may be mapped different
/// places. Probably want to implement `SparseAddressSpace` (collection of
/// `AbsoluteAddressSpace`s)  for this.
///
/// Note that this implements `AddressSpace<VA>` and not `AddressSpace<RVA>`.
/// Use `RelativeAddressSpace` when you're dealing with relative addresses
/// (`RVA`).
#[derive(Clone)]
pub struct AbsoluteAddressSpace {
    pub base_address: VA,

    /// The inner relative address space with data mapped at `base_address`.
    /// Its ok to reach into this address space if you've got RVAs relative to
    /// `base_address`.
    pub relative: RelativeAddressSpace,
}

impl AddressSpace<VA> for AbsoluteAddressSpace {
    fn read_into(&self, offset: VA, buf: &mut [u8]) -> Result<()> {
        if offset < self.base_address {
            return Err(PageMapError::NotMapped.into());
        }

        self.relative.read_into((offset - self.base_address) as RVA, buf)
    }

    fn read_ascii(&self, offset: VA) -> Result<String> {
        if offset < self.base_address {
            return Err(PageMapError::NotMapped.into());
        }

        self.relative.read_ascii((offset - self.base_address) as RVA)
    }
}
<|endoftext|>


<commit_before>/// Macro for implementing `Entrypoint` or `DecodedEntryPoint` boilerplate in an algorithm
///
/// Algorithmia support for Rust algorithms is hard-coded to call `Algo::apply(AlgoInput)`
///   but for the sake of convenience the `EntryPoint` trait provides a default implementation
///   of `apply` that delegates to `apply_str`, `apply_bytes`, or `apply_json` depending on
///   the variant of `AlgoInput`. The `DecodedEntryPoint` trait overrides the default `apply`
///   to provide a method that uses a deserialized associated type when calling `apply_decoded`.
///   This pattern is incredibly flexible, but adds boilerplate and still requires
///   converting output and error types back.
///
/// The `algo_entrypoint!` macro hides all that boilerplate code behind a single macro invocation.
///   `algo_entrypoint(type => your_fn)` wires up the boilerplate for calling `your_fn(type)`.
///   Additionally, you can use the macro as `algo_entrypoint(type)` which is equivalent to
///   `algo_entrypoint!(type => apply)`.
///
/// Use the following types:
///
/// - `&str` if your algorithm accepts text input
/// - `&[u8]` if your algorithm accepts binary input
/// - Any deserializeable type if your algorithm accepts JSON input
/// - `&JsonValue` is you want your algorithm to work directly with the typed JSON input
/// - `AlgoInput` if you want to work with the full enum of possible input types
///
/// In all cases, the return value of `your_fn` should be `Result<T, E>` where:
///
/// - `T` implements `Into<AlgoOutput>` which includes `String`, `Vec<u8>`, `JsonValue`, and boxed* serializeable types
/// - `E` implements `Into<Box<::std::error::Error>>` which includes `String` and all `Error` types
///
/// ** support for unboxed serializeable depends on specialization implemented behind the 'nightly' feature.*
///
/// # Examples
///
/// ## Text Input/Output
/// To set the entrypoint to a function that receives and returns text:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&str);
///
/// fn apply(input: &str) -> Result<String, String> {
///     unimplemented!()
/// }
/// ```
///
/// which generates:
///
/// ```ignore
/// #[derive(Default)]
/// pub struct Algo;
///
/// impl EntryPoint for Algo {
///     fn apply_str(&self, input: &str) -> Result<AlgoOutput, Box<::std::error::Error>> {
///         apply(input).map(AlgoOutput::from).map_err(|err| err.into())
///     }
/// }
///
/// fn apply(input: &str) -> Result<String, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## Binary Input/Output
/// To set the entrypoint to a function that receives and returns binary data:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&[u8]);
///
/// fn apply(input: &[u8]) -> Result<Vec<u8>, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## JSON Input/Output
/// To set the entrypoint to a function that receives and returns JSON data,
///   you can work directly with the `JsonValue`:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&JsonValue);
///
/// fn apply(input: &JsonValue) -> Result<JsonValue, String> {
///     unimplemented!()
/// }
/// ```
///
/// Although, often the preferred way to work with JSON is to automatically
///   deserialize into and serialize from a custom type.
///
/// ```ignore
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// #[derive(Deserialize)]
/// pub struct MyInput { corpus: String, msg: String }
///
/// #[derive(Serialize)]
/// pub struct MyOutput { probabilities: Vec<(String, f32)> }
///
/// algo_entrypoint!(MyInput);
///
/// fn apply(input: MyInput) -> Result<Box<MyOutput>, String> {
///     unimplemented!()
/// }
/// ```
///
/// Note: `Box` for serializeable output is currently required for lack of specialization.
///   The specialization implementation already exists behind the `nightly` feature.
///   Alternatively, you can return `AlgoOutput` via `AlgoOutput::from(&myOutput)`
///
/// The previous example expands into:
///
/// ```ignore
/// #[derive(Deserialize)]
/// pub struct MyInput { corpus: String, msg: String };
///
/// #[derive(Serialize)]
/// pub struct MyOutput { probabilities: Vec<(String, f32)> };
///
/// #[derive(Default)]
/// pub struct Algo;
///
/// impl DecodedEntryPoint for Algo {
///     type Input (String, String);
///     fn apply_decoded(&self, input: MyInput) -> Result<AlgoOutput, Box<::std::error::Error>> {
///         apply(input).map(AlgoOutput::from).map_err(|err| err.into())
///     }
/// }
///
/// fn apply(input: MyInput) -> Result<Box<MyOutput>, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## Customizing `Default`
/// And finally, it is possible to provide a custom `Default` implementation
///   and pass that state into your method by prefixing `your_fn` with
///   the `Algo::` namespace.
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// pub struct Algo{ init_id: String }
///
/// algo_entrypoint!(&str => Algo::hello_text);
///
/// impl Algo {
///     fn hello_text(&self, input: &str) -> Result<String, String> {
///         unimplemented!()
///     }
/// }
///
/// impl Default for Algo {
///     fn default() -> Algo {
///         Algo { init_id: "foo".into() }
///     }
/// }
/// ```
#[macro_export]
macro_rules! algo_entrypoint {
    // Helpers for recursively implementing text/bytes/JsonValue/AlgoInput
    ($t:ty, $apply:ident, Algo::$method:ident) => {
        impl EntryPoint for Algo {
            fn $apply(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
                self.$method(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
    ($t:ty, $apply:ident, $p:path) => {
        #[derive(Default)] pub struct Algo;
        impl EntryPoint for Algo {
            fn $apply(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
                $p(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
    // Implement short-hand variants using free apply function
    (&str) => {
        algo_entrypoint!(&str => apply);
    };
    (&[u8]) => {
        algo_entrypoint!(&[u8] => apply);
    };
    (&JsonValue) => {
        algo_entrypoint!(&JsonValue => apply);
    };
    (AlgoInput) => {
        algo_entrypoint!(AlgoInput => apply);
    };
    ($t:ty) => {
        algo_entrypoint!($t => apply);
    };

    // Implement EntryPoint to call methods on `Algo`
    (&str => Algo::$i:ident) => {
        algo_entrypoint!(&str, apply_str, Algo::$i);
    };
    (&[u8] => Algo::$i:ident) => {
        algo_entrypoint!(&[u8], apply_bytes, Algo::$i);
    };
    (&JsonValue => Algo::$i:ident) => {
        algo_entrypoint!(&JsonValue, apply_json, Algo::$i);
    };
    (AlgoInput => Algo::$i:ident) => {
        algo_entrypoint!(AlgoInput, apply, Algo::$i);
    };
    ($t:ty => Algo::$i:ident) => {
        impl DecodedEntryPoint for Algo {
            type Input = $t;
            fn apply_bytes(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
                self.$i(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };

    // Implement EntryPoint to call free functions
    (&str => $p:path) => {
        algo_entrypoint!(&str, apply_str, $p);
    };
    (&[u8] => $p:path) => {
        algo_entrypoint!(&[u8], apply_bytes, $p);
    };
    (&JsonValue => $p:path) => {
        algo_entrypoint!(&JsonValue, apply_json, $p);
    };
    (AlgoInput => $p:path) => {
        algo_entrypoint!(AlgoInput, apply, $p);
    };

    ($t:ty => $p:path) => {
        #[derive(Default)] pub struct Algo;
        impl DecodedEntryPoint for Algo {
            type Input = $t;
            fn apply_decoded(&self, input: $t) -> Result<AlgoOutput, Box<::std::error::Error>> {
                $p(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
}

// Testing all the variants with unused code
mod test_str {
    use prelude::*;
    algo_entrypoint!(&str => hello_text);
    fn hello_text(_input: &str) -> Result<String, String> {
        unimplemented!()
    }
}

mod test_bytes {
    use prelude::*;
    algo_entrypoint!(&[u8] => hello_bytes);
    fn hello_bytes(_input: &[u8]) -> Result<Vec<u8>, String> {
        unimplemented!()
    }
}

mod test_json {
    use prelude::*;
    algo_entrypoint!(&JsonValue => hello_json);
    fn hello_json(_input: &JsonValue) -> Result<JsonValue, String> {
        unimplemented!()
    }
}

mod test_enum {
    use prelude::*;
    algo_entrypoint!(AlgoInput => hello_enum);
    fn hello_enum(_input: AlgoInput) -> Result<AlgoOutput, String> {
        unimplemented!()
    }
}

mod test_decode {
    use prelude::*;

    #[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable, RustcEncodable))]
    #[cfg_attr(feature="with-serde", derive(Deserialize, Serialize))]
    pub struct Custom {
        foo: String,
        bar: Vec<u32>,
        baz: bool,
    }
    algo_entrypoint!(Custom => hello_decoded);
    fn hello_decoded(_input: Custom) -> Result<Box<Custom>, String> {
        unimplemented!()
    }
}

mod test_shorthand_str {
    use prelude::*;
    algo_entrypoint!(&str => apply);
    fn apply(_input: &str) -> Result<String, String> {
        unimplemented!()
    }
}

mod test_shorthand_bytes {
    use prelude::*;
    algo_entrypoint!(&[u8]);
    fn apply(_input: &[u8]) -> Result<Vec<u8>, String> {
        unimplemented!()
    }
}

mod test_shorthand_json {
    use prelude::*;
    algo_entrypoint!(&JsonValue);
    fn apply(_input: &JsonValue) -> Result<JsonValue, String> {
        unimplemented!()
    }
}

mod test_shorthand_enum {
    use prelude::*;
    algo_entrypoint!(AlgoInput);
    fn apply(_input: AlgoInput) -> Result<AlgoOutput, String> {
        unimplemented!()
    }
}

mod test_shorthand_decode {
    use prelude::*;

    #[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable, RustcEncodable))]
    #[cfg_attr(feature="with-serde", derive(Deserialize, Serialize))]
    pub struct Custom {
        foo: String,
        bar: Vec<u32>,
        baz: bool,
    }
    algo_entrypoint!(Custom);
    fn apply(_input: Custom) -> Result<Box<Custom>, String> {
        unimplemented!()
    }
}
<commit_msg>use fully qualified path to Result for macros<commit_after>/// Macro for implementing `Entrypoint` or `DecodedEntryPoint` boilerplate in an algorithm
///
/// Algorithmia support for Rust algorithms is hard-coded to call `Algo::apply(AlgoInput)`
///   but for the sake of convenience the `EntryPoint` trait provides a default implementation
///   of `apply` that delegates to `apply_str`, `apply_bytes`, or `apply_json` depending on
///   the variant of `AlgoInput`. The `DecodedEntryPoint` trait overrides the default `apply`
///   to provide a method that uses a deserialized associated type when calling `apply_decoded`.
///   This pattern is incredibly flexible, but adds boilerplate and still requires
///   converting output and error types back.
///
/// The `algo_entrypoint!` macro hides all that boilerplate code behind a single macro invocation.
///   `algo_entrypoint(type => your_fn)` wires up the boilerplate for calling `your_fn(type)`.
///   Additionally, you can use the macro as `algo_entrypoint(type)` which is equivalent to
///   `algo_entrypoint!(type => apply)`.
///
/// Use the following types:
///
/// - `&str` if your algorithm accepts text input
/// - `&[u8]` if your algorithm accepts binary input
/// - Any deserializeable type if your algorithm accepts JSON input
/// - `&JsonValue` is you want your algorithm to work directly with the typed JSON input
/// - `AlgoInput` if you want to work with the full enum of possible input types
///
/// In all cases, the return value of `your_fn` should be `Result<T, E>` where:
///
/// - `T` implements `Into<AlgoOutput>` which includes `String`, `Vec<u8>`, `JsonValue`, and boxed* serializeable types
/// - `E` implements `Into<Box<::std::error::Error>>` which includes `String` and all `Error` types
///
/// ** support for unboxed serializeable depends on specialization implemented behind the 'nightly' feature.*
///
/// # Examples
///
/// ## Text Input/Output
/// To set the entrypoint to a function that receives and returns text:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&str);
///
/// fn apply(input: &str) -> Result<String, String> {
///     unimplemented!()
/// }
/// ```
///
/// which generates:
///
/// ```ignore
/// #[derive(Default)]
/// pub struct Algo;
///
/// impl EntryPoint for Algo {
///     fn apply_str(&self, input: &str) -> Result<AlgoOutput, Box<::std::error::Error>> {
///         apply(input).map(AlgoOutput::from).map_err(|err| err.into())
///     }
/// }
///
/// fn apply(input: &str) -> Result<String, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## Binary Input/Output
/// To set the entrypoint to a function that receives and returns binary data:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&[u8]);
///
/// fn apply(input: &[u8]) -> Result<Vec<u8>, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## JSON Input/Output
/// To set the entrypoint to a function that receives and returns JSON data,
///   you can work directly with the `JsonValue`:
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// algo_entrypoint!(&JsonValue);
///
/// fn apply(input: &JsonValue) -> Result<JsonValue, String> {
///     unimplemented!()
/// }
/// ```
///
/// Although, often the preferred way to work with JSON is to automatically
///   deserialize into and serialize from a custom type.
///
/// ```ignore
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// #[derive(Deserialize)]
/// pub struct MyInput { corpus: String, msg: String }
///
/// #[derive(Serialize)]
/// pub struct MyOutput { probabilities: Vec<(String, f32)> }
///
/// algo_entrypoint!(MyInput);
///
/// fn apply(input: MyInput) -> Result<Box<MyOutput>, String> {
///     unimplemented!()
/// }
/// ```
///
/// Note: `Box` for serializeable output is currently required for lack of specialization.
///   The specialization implementation already exists behind the `nightly` feature.
///   Alternatively, you can return `AlgoOutput` via `AlgoOutput::from(&myOutput)`
///
/// The previous example expands into:
///
/// ```ignore
/// #[derive(Deserialize)]
/// pub struct MyInput { corpus: String, msg: String };
///
/// #[derive(Serialize)]
/// pub struct MyOutput { probabilities: Vec<(String, f32)> };
///
/// #[derive(Default)]
/// pub struct Algo;
///
/// impl DecodedEntryPoint for Algo {
///     type Input (String, String);
///     fn apply_decoded(&self, input: MyInput) -> Result<AlgoOutput, Box<::std::error::Error>> {
///         apply(input).map(AlgoOutput::from).map_err(|err| err.into())
///     }
/// }
///
/// fn apply(input: MyInput) -> Result<Box<MyOutput>, String> {
///     unimplemented!()
/// }
/// ```
///
/// ## Customizing `Default`
/// And finally, it is possible to provide a custom `Default` implementation
///   and pass that state into your method by prefixing `your_fn` with
///   the `Algo::` namespace.
///
/// ```no_run
/// # #[macro_use] extern crate algorithmia;
/// # fn main() {}
/// # use algorithmia::prelude::*;
/// pub struct Algo{ init_id: String }
///
/// algo_entrypoint!(&str => Algo::hello_text);
///
/// impl Algo {
///     fn hello_text(&self, input: &str) -> Result<String, String> {
///         unimplemented!()
///     }
/// }
///
/// impl Default for Algo {
///     fn default() -> Algo {
///         Algo { init_id: "foo".into() }
///     }
/// }
/// ```
#[macro_export]
macro_rules! algo_entrypoint {
    // Helpers for recursively implementing text/bytes/JsonValue/AlgoInput
    ($t:ty, $apply:ident, Algo::$method:ident) => {
        impl EntryPoint for Algo {
            fn $apply(&self, input: $t) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                self.$method(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
    ($t:ty, $apply:ident, $p:path) => {
        #[derive(Default)] pub struct Algo;
        impl EntryPoint for Algo {
            fn $apply(&self, input: $t) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                $p(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
    // Implement short-hand variants using free apply function
    (&str) => {
        algo_entrypoint!(&str => apply);
    };
    (&[u8]) => {
        algo_entrypoint!(&[u8] => apply);
    };
    (&JsonValue) => {
        algo_entrypoint!(&JsonValue => apply);
    };
    (AlgoInput) => {
        algo_entrypoint!(AlgoInput => apply);
    };
    ($t:ty) => {
        algo_entrypoint!($t => apply);
    };

    // Implement EntryPoint to call methods on `Algo`
    (&str => Algo::$i:ident) => {
        algo_entrypoint!(&str, apply_str, Algo::$i);
    };
    (&[u8] => Algo::$i:ident) => {
        algo_entrypoint!(&[u8], apply_bytes, Algo::$i);
    };
    (&JsonValue => Algo::$i:ident) => {
        algo_entrypoint!(&JsonValue, apply_json, Algo::$i);
    };
    (AlgoInput => Algo::$i:ident) => {
        algo_entrypoint!(AlgoInput, apply, Algo::$i);
    };
    ($t:ty => Algo::$i:ident) => {
        impl DecodedEntryPoint for Algo {
            type Input = $t;
            fn apply_bytes(&self, input: $t) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                self.$i(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };

    // Implement EntryPoint to call free functions
    (&str => $p:path) => {
        algo_entrypoint!(&str, apply_str, $p);
    };
    (&[u8] => $p:path) => {
        algo_entrypoint!(&[u8], apply_bytes, $p);
    };
    (&JsonValue => $p:path) => {
        algo_entrypoint!(&JsonValue, apply_json, $p);
    };
    (AlgoInput => $p:path) => {
        algo_entrypoint!(AlgoInput, apply, $p);
    };

    ($t:ty => $p:path) => {
        #[derive(Default)] pub struct Algo;
        impl DecodedEntryPoint for Algo {
            type Input = $t;
            fn apply_decoded(&self, input: $t) -> ::std::result::Result<AlgoOutput, Box<::std::error::Error>> {
                $p(input).map(AlgoOutput::from).map_err(|err| err.into())
            }
        }
    };
}

// Testing all the variants with unused code
mod test_str {
    use prelude::*;
    algo_entrypoint!(&str => hello_text);
    fn hello_text(_input: &str) -> Result<String, String> {
        unimplemented!()
    }
}

mod test_bytes {
    use prelude::*;
    algo_entrypoint!(&[u8] => hello_bytes);
    fn hello_bytes(_input: &[u8]) -> Result<Vec<u8>, String> {
        unimplemented!()
    }
}

mod test_json {
    use prelude::*;
    algo_entrypoint!(&JsonValue => hello_json);
    fn hello_json(_input: &JsonValue) -> Result<JsonValue, String> {
        unimplemented!()
    }
}

mod test_enum {
    use prelude::*;
    algo_entrypoint!(AlgoInput => hello_enum);
    fn hello_enum(_input: AlgoInput) -> Result<AlgoOutput, String> {
        unimplemented!()
    }
}

mod test_decode {
    use prelude::*;

    #[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable, RustcEncodable))]
    #[cfg_attr(feature="with-serde", derive(Deserialize, Serialize))]
    pub struct Custom {
        foo: String,
        bar: Vec<u32>,
        baz: bool,
    }
    algo_entrypoint!(Custom => hello_decoded);
    fn hello_decoded(_input: Custom) -> Result<Box<Custom>, String> {
        unimplemented!()
    }
}

mod test_shorthand_str {
    use prelude::*;
    algo_entrypoint!(&str => apply);
    fn apply(_input: &str) -> Result<String, String> {
        unimplemented!()
    }
}

mod test_shorthand_bytes {
    use prelude::*;
    algo_entrypoint!(&[u8]);
    fn apply(_input: &[u8]) -> Result<Vec<u8>, String> {
        unimplemented!()
    }
}

mod test_shorthand_json {
    use prelude::*;
    algo_entrypoint!(&JsonValue);
    fn apply(_input: &JsonValue) -> Result<JsonValue, String> {
        unimplemented!()
    }
}

mod test_shorthand_enum {
    use prelude::*;
    algo_entrypoint!(AlgoInput);
    fn apply(_input: AlgoInput) -> Result<AlgoOutput, String> {
        unimplemented!()
    }
}

mod test_shorthand_decode {
    use prelude::*;

    #[cfg_attr(feature="with-rustc-serialize", derive(RustcDecodable, RustcEncodable))]
    #[cfg_attr(feature="with-serde", derive(Deserialize, Serialize))]
    pub struct Custom {
        foo: String,
        bar: Vec<u32>,
        baz: bool,
    }
    algo_entrypoint!(Custom);
    fn apply(_input: Custom) -> Result<Box<Custom>, String> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(i32);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let mut attribute_list = vec!();

        if use_gles2 {
            attribute_list.push_all(&[
                ffi::egl::RENDERABLE_TYPE as i32,
                ffi::egl::OPENGL_ES2_BIT as i32,
            ]);
        }

        {
            let (red, green, blue) = match builder.color_bits.unwrap_or(24) {
                24 => (8, 8, 8),
                16 => (6, 5, 6),
                _ => panic!("Bad color_bits"),
            };
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, red]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, green]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, blue]);
        }

        attribute_list.push_all(&[
            ffi::egl::DEPTH_SIZE as i32,
            builder.depth_bits.unwrap_or(8) as i32,
        ]);

        attribute_list.push(ffi::egl::NONE as i32);

        let config = unsafe {
            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> RingBuf<Event> {
        let mut events = RingBuf::new();
        loop {
            match self.event_rx.try_recv() {
                Ok(event) => match event {
                    android_glue::Event::EventDown => {
                        events.push_back(MouseInput(Pressed, MouseButton::Left));
                    },
                    android_glue::Event::EventUp => {
                        events.push_back(MouseInput(Released, MouseButton::Left));
                    },
                    android_glue::Event::EventMove(x, y) => {
                        events.push_back(MouseMoved((x as i32, y as i32)));
                    },
                },
                Err(_) => {
                    break;
                },
            }
        }
        events
    }

    pub fn wait_events(&self) -> RingBuf<Event> {
        use std::time::Duration;
        use std::old_io::timer;
        timer::sleep(Duration::milliseconds(16));
        self.poll_events()
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let addr = CString::from_slice(addr.as_bytes());
        let addr = addr.as_slice_with_nul().as_ptr();
        unsafe {
            ffi::egl::GetProcAddress(addr) as *const ()
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    pub fn set_cursor(&self, _: MouseCursor) {
    }

    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<commit_msg>Android: Use platform specific iterators.<commit_after>extern crate android_glue;

use libc;
use std::ffi::{CString};
use std::sync::mpsc::{Receiver, channel};
use {CreationError, Event, MouseCursor};
use CreationError::OsError;
use events::ElementState::{Pressed, Released};
use events::Event::{MouseInput, MouseMoved};
use events::MouseButton;

use std::collections::RingBuf;

use BuilderAttribs;

pub struct Window {
    display: ffi::egl::types::EGLDisplay,
    context: ffi::egl::types::EGLContext,
    surface: ffi::egl::types::EGLSurface,
    event_rx: Receiver<android_glue::Event>,
}

pub struct MonitorID;

mod ffi;

pub fn get_available_monitors() -> RingBuf <MonitorID> {
    let mut rb = RingBuf::new();
    rb.push_back(MonitorID);
    rb
}

pub fn get_primary_monitor() -> MonitorID {
    MonitorID
}

impl MonitorID {
    pub fn get_name(&self) -> Option<String> {
        Some("Primary".to_string())
    }

    pub fn get_dimensions(&self) -> (u32, u32) {
        unimplemented!()
    }
}

#[cfg(feature = "headless")]
pub struct HeadlessContext(i32);

#[cfg(feature = "headless")]
impl HeadlessContext {
    /// See the docs in the crate root file.
    pub fn new(_builder: BuilderAttribs) -> Result<HeadlessContext, CreationError> {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub unsafe fn make_current(&self) {
        unimplemented!()
    }

    /// See the docs in the crate root file.
    pub fn get_proc_address(&self, _addr: &str) -> *const () {
        unimplemented!()
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }
}

#[cfg(feature = "headless")]
unsafe impl Send for HeadlessContext {}
#[cfg(feature = "headless")]
unsafe impl Sync for HeadlessContext {}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        match self.window.event_rx.try_recv() {
            Ok(event) => {
                Some(match event {
                    android_glue::Event::EventDown => MouseInput(Pressed, MouseButton::Left),
                    android_glue::Event::EventUp => MouseInput(Released, MouseButton::Left),
                    android_glue::Event::EventMove(x, y) => MouseMoved((x as i32, y as i32)),
                })
            }
            Err(_) => {
                None
            }
        }
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        use std::time::Duration;
        use std::old_io::timer;

        loop {
            // calling poll_events()
            if let Some(ev) = self.window.poll_events().next() {
                return Some(ev);
            }

            // TODO: Implement a proper way of sleeping on the event queue
            timer::sleep(Duration::milliseconds(16));
        }
    }
}

impl Window {
    pub fn new(builder: BuilderAttribs) -> Result<Window, CreationError> {
        use std::{mem, ptr};

        if builder.sharing.is_some() {
            unimplemented!()
        }

        let native_window = unsafe { android_glue::get_native_window() };
        if native_window.is_null() {
            return Err(OsError(format!("Android's native window is null")));
        }

        let display = unsafe {
            let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY));
            if display.is_null() {
                return Err(OsError("No EGL display connection available".to_string()));
            }
            display
        };

        android_glue::write_log("eglGetDisplay succeeded");

        let (_major, _minor) = unsafe {
            let mut major: ffi::egl::types::EGLint = mem::uninitialized();
            let mut minor: ffi::egl::types::EGLint = mem::uninitialized();

            if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 {
                return Err(OsError(format!("eglInitialize failed")))
            }

            (major, minor)
        };

        android_glue::write_log("eglInitialize succeeded");

        let use_gles2 = match builder.gl_version {
            Some((2, 0)) => true,
            _ => false,
        };

        let mut attribute_list = vec!();

        if use_gles2 {
            attribute_list.push_all(&[
                ffi::egl::RENDERABLE_TYPE as i32,
                ffi::egl::OPENGL_ES2_BIT as i32,
            ]);
        }

        {
            let (red, green, blue) = match builder.color_bits.unwrap_or(24) {
                24 => (8, 8, 8),
                16 => (6, 5, 6),
                _ => panic!("Bad color_bits"),
            };
            attribute_list.push_all(&[ffi::egl::RED_SIZE as i32, red]);
            attribute_list.push_all(&[ffi::egl::GREEN_SIZE as i32, green]);
            attribute_list.push_all(&[ffi::egl::BLUE_SIZE as i32, blue]);
        }

        attribute_list.push_all(&[
            ffi::egl::DEPTH_SIZE as i32,
            builder.depth_bits.unwrap_or(8) as i32,
        ]);

        attribute_list.push(ffi::egl::NONE as i32);

        let config = unsafe {
            let mut num_config: ffi::egl::types::EGLint = mem::uninitialized();
            let mut config: ffi::egl::types::EGLConfig = mem::uninitialized();
            if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1,
                &mut num_config) == 0
            {
                return Err(OsError(format!("eglChooseConfig failed")))
            }

            if num_config <= 0 {
                return Err(OsError(format!("eglChooseConfig returned no available config")))
            }

            config
        };

        android_glue::write_log("eglChooseConfig succeeded");

        let context = unsafe {
            let mut context_attributes = vec!();
            if use_gles2 {
                context_attributes.push_all(&[ffi::egl::CONTEXT_CLIENT_VERSION as i32, 2]);
            }
            context_attributes.push(ffi::egl::NONE as i32);

            let context = ffi::egl::CreateContext(display, config, ptr::null(),
                                                  context_attributes.as_ptr());
            if context.is_null() {
                return Err(OsError(format!("eglCreateContext failed")))
            }
            context
        };

        android_glue::write_log("eglCreateContext succeeded");

        let surface = unsafe {
            let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null());
            if surface.is_null() {
                return Err(OsError(format!("eglCreateWindowSurface failed")))
            }
            surface
        };

        android_glue::write_log("eglCreateWindowSurface succeeded");

        let (tx, rx) = channel();
        android_glue::add_sender(tx);

        Ok(Window {
            display: display,
            context: context,
            surface: surface,
            event_rx: rx,
        })
    }

    pub fn is_closed(&self) -> bool {
        false
    }

    pub fn set_title(&self, _: &str) {
    }

    pub fn show(&self) {
    }

    pub fn hide(&self) {
    }

    pub fn get_position(&self) -> Option<(i32, i32)> {
        None
    }

    pub fn set_position(&self, _x: i32, _y: i32) {
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        let native_window = unsafe { android_glue::get_native_window() };

        if native_window.is_null() {
            None
        } else {
            Some((
                unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32,
                unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32
            ))
        }
    }

    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        self.get_inner_size()
    }

    pub fn set_inner_size(&self, _x: u32, _y: u32) {
    }

    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    pub fn make_current(&self) {
        unsafe {
            ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context);
        }
    }

    pub fn get_proc_address(&self, addr: &str) -> *const () {
        let addr = CString::from_slice(addr.as_bytes());
        let addr = addr.as_slice_with_nul().as_ptr();
        unsafe {
            ffi::egl::GetProcAddress(addr) as *const ()
        }
    }

    pub fn swap_buffers(&self) {
        unsafe {
            ffi::egl::SwapBuffers(self.display, self.surface);
        }
    }

    pub fn platform_display(&self) -> *mut libc::c_void {
        self.display as *mut libc::c_void
    }

    pub fn get_api(&self) -> ::Api {
        ::Api::OpenGlEs
    }

    pub fn set_window_resize_callback(&mut self, _: Option<fn(u32, u32)>) {
    }

    pub fn set_cursor(&self, _: MouseCursor) {
    }

    pub fn hidpi_factor(&self) -> f32 {
        1.0
    }
}

unsafe impl Send for Window {}
unsafe impl Sync for Window {}

#[cfg(feature = "window")]
#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            android_glue::write_log("Destroying gl-init window");
            ffi::egl::MakeCurrent(self.display, ptr::null(), ptr::null(), ptr::null());
            ffi::egl::DestroySurface(self.display, self.surface);
            ffi::egl::DestroyContext(self.display, self.context);
            ffi::egl::Terminate(self.display);
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use super::{Array, Dimension};

/// HACK: fmt::rt::FlagAlternate has been hidden away
const FlagAlternate: usize = 2;

fn format_array<A, D: Dimension, F>(view: &Array<A, D>, f: &mut fmt::Formatter,
                                    mut format: F) -> fmt::Result where
    F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
{
    let ndim = view.dim.slice().len();
    /* private nowadays
    if ndim > 0 && f.width.is_none() {
        f.width = Some(4)
    }
    */
    // None will be an empty iter.
    let mut last_index = match view.dim.first_index() {
        None => view.dim.clone(),
        Some(ix) => ix,
    };
    for _ in (0..ndim) {
        try!(write!(f, "["));
    }
    let mut first = true;
    // Simply use the indexed iterator, and take the index wraparounds
    // as cues for when to add []'s and how many to add.
    for (index, elt) in view.indexed_iter() {
        let take_n = if ndim == 0 { 1 } else { ndim - 1 };
        let mut update_index = false;
        for (i, (a, b)) in index.slice().iter().take(take_n)
                        .zip(last_index.slice().iter())
                        .enumerate()
        {
            if a != b {
                // New row.
                // # of ['s needed
                let n = ndim - i - 1;
                for _ in (0..n) {
                    try!(write!(f, "]"));
                }
                try!(write!(f, ","));
                if f.flags() & (1 << FlagAlternate) == 0 {
                    try!(write!(f, "\n"));
                }
                for _ in (0..ndim - n) {
                    try!(write!(f, " "));
                }
                for _ in (0..n) {
                    try!(write!(f, "["));
                }
                first = true;
                update_index = true;
                break;
            }
        }
        if !first {
            try!(write!(f, ", "));
        }
        first = false;
        try!(format(f, elt));

        if update_index {
            last_index = index;
        }
    }
    for _ in (0..ndim) {
        try!(write!(f, "]"));
    }
    Ok(())
}

// NOTE: We can impl other fmt traits here
impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array<A, D>
{
    /// Format the array using `Display` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array<A, D>
{
    /// Format the array using `Debug` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::LowerExp, D: Dimension> fmt::LowerExp for Array<A, D>
{
    /// Format the array using `LowerExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#e}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::UpperExp, D: Dimension> fmt::UpperExp for Array<A, D>
{
    /// Format the array using `UpperExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#E}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

<commit_msg>Fix case warning<commit_after>use std::fmt;
use super::{Array, Dimension};

/// HACK: fmt::rt::FlagAlternate has been hidden away
const FLAG_ALTERNATE: usize = 2;

fn format_array<A, D: Dimension, F>(view: &Array<A, D>, f: &mut fmt::Formatter,
                                    mut format: F) -> fmt::Result where
    F: FnMut(&mut fmt::Formatter, &A) -> fmt::Result,
{
    let ndim = view.dim.slice().len();
    /* private nowadays
    if ndim > 0 && f.width.is_none() {
        f.width = Some(4)
    }
    */
    // None will be an empty iter.
    let mut last_index = match view.dim.first_index() {
        None => view.dim.clone(),
        Some(ix) => ix,
    };
    for _ in (0..ndim) {
        try!(write!(f, "["));
    }
    let mut first = true;
    // Simply use the indexed iterator, and take the index wraparounds
    // as cues for when to add []'s and how many to add.
    for (index, elt) in view.indexed_iter() {
        let take_n = if ndim == 0 { 1 } else { ndim - 1 };
        let mut update_index = false;
        for (i, (a, b)) in index.slice().iter().take(take_n)
                        .zip(last_index.slice().iter())
                        .enumerate()
        {
            if a != b {
                // New row.
                // # of ['s needed
                let n = ndim - i - 1;
                for _ in (0..n) {
                    try!(write!(f, "]"));
                }
                try!(write!(f, ","));
                if f.flags() & (1 << FLAG_ALTERNATE) == 0 {
                    try!(write!(f, "\n"));
                }
                for _ in (0..ndim - n) {
                    try!(write!(f, " "));
                }
                for _ in (0..n) {
                    try!(write!(f, "["));
                }
                first = true;
                update_index = true;
                break;
            }
        }
        if !first {
            try!(write!(f, ", "));
        }
        first = false;
        try!(format(f, elt));

        if update_index {
            last_index = index;
        }
    }
    for _ in (0..ndim) {
        try!(write!(f, "]"));
    }
    Ok(())
}

// NOTE: We can impl other fmt traits here
impl<'a, A: fmt::Display, D: Dimension> fmt::Display for Array<A, D>
{
    /// Format the array using `Display` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::Debug, D: Dimension> fmt::Debug for Array<A, D>
{
    /// Format the array using `Debug` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::LowerExp, D: Dimension> fmt::LowerExp for Array<A, D>
{
    /// Format the array using `LowerExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#e}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

impl<'a, A: fmt::UpperExp, D: Dimension> fmt::UpperExp for Array<A, D>
{
    /// Format the array using `UpperExp` and apply the formatting parameters used
    /// to each element.
    ///
    /// The array is shown in multiline style, unless the alternate form
    /// is used -- i.e. `{:#E}`.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        format_array(self, f, |f, elt| elt.fmt(f))
    }
}

<|endoftext|>