<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.

// The crazy macro_rules magic in this file is thanks to dtolnay@
// and is a way of attaching rustdoc to each of the possible directives
// within the include_cpp outer macro. None of the directives actually
// do anything - all the magic is handled entirely by
// autocxx_macro::include_cpp_impl.

/// Include some C++ headers in your Rust project.
///
/// This macro allows you to include one or more C++ headers within
/// your Rust code, and call their functions fairly naturally.
///
/// # Examples
///
/// C++ header (`input.h`):
/// ```cpp
/// #include <cstdint>
///
/// uint32_t do_math(uint32_t a);
/// ```
///
/// Rust code:
/// ```
/// # use autocxx_macro::include_cpp_impl as include_cpp;
/// include_cpp!(
///     unsafe
/// #   parse_only
///     #include "input.h"
///     generate!("do_math")
/// );
///
/// # mod ffi { pub fn do_math(a: u32) -> u32 { a+3 } }
/// # fn main() {
/// ffi::do_math(3);
/// # }
/// ```
///
/// # Configuring the build
///
/// To build this, you'll need to:
/// * Build the C++ side of the bindings. You'll need to use the `autocxx-gen`
///   crate or the `autocxx-build` crate to process the .rs code into C++ header and
///   implementation files.
/// * Educate the procedural macro about where to find the C++ headers. Set the
///   `AUTOCXX_INC` environment variable to a list of directories to search.
///   If you use `autocxx-build`, this happens automatically.

///
/// # Syntax
///
/// Within the brackets of the `include_cxx!(...)` macro, you should provide
/// a list of at least the following:
///
/// * the `unsafe` keyword (must always come first)
/// * `#include "cpp_header.h"`: a header filename to parse and include
/// * `generate!("type_or_function_name")`: a type or function name whose declaration
///   should be made available to C++.
///
/// Other directives are possible as documented in this crate.
///
/// # How to generate structs
///
/// All C++ types can be owned within a [UniquePtr][autocxx_engine::cxx::UniquePtr]
/// within Rust. To let this be possible, simply pass the names of these
/// types within [generate] (or just [generate] any function which requires these types).
///
/// However, only _some_ C++ `struct`s can be owned _by value_ within Rust. Those
/// types must be freely byte-copyable, because Rust is free to do that at
/// any time. If you believe your `struct` meets those criteria, you can
/// use [generate_pod] instead.
///
/// Use [generate] under normal circumstances, but [generate_pod] only for structs
/// where you absolutely do need to pass them truly by value and have direct field access.
///
/// This doesn't just make a difference to the generated code for the type;
/// it also makes a difference to any functions which take or return that type.
/// If there's a C++ function which takes a struct by value, but that struct
/// is not declared as POD-safe, then we'll generate wrapper functions to move
/// that type into and out of [UniquePtr][autocxx_engine::cxx::UniquePtr]s.
///
/// # Generated code
///
/// You will find that this macro expands to the equivalent of:
///
/// ```no_run
/// mod ffi {
///     pub fn do_math(a: u32) -> u32
/// #   { a+3 }
///     pub const kMyCxxConst: i32 = 3;
///     pub const MY_PREPROCESSOR_DEFINITION: i64 = 3i64;
/// }
/// ```
///
/// # Built-in types
///
/// The generated code uses `cxx` for interop: see that crate for many important
/// considerations including safety and the list of built-in types, for example
/// [UniquePtr][autocxx_engine::cxx::UniquePtr] and
/// [CxxString][autocxx_engine::cxx::CxxString].
///
/// # Making strings
///
/// Unless you use [exclude_utilities], you will find a trait called
/// `ffi::ToCppString` which you can use to convert any Rust string into a C++
/// `std::unique_ptr<std::string>` like this:
///
/// ```ignore
/// use ffi::ToCpp;
/// let unique_ptr_to_cxx_string = "my_string".to_cpp();
/// ```
///
/// # Making other C++ types
///
/// Types gain a `make_unique` associated function. At present they only
/// gain this if they have an explicit C++ constructor; this is a limitation
/// which should be resolved in future.
/// This will (of course) return a `UniquePtr` containing that type.
///
/// # Preprocessor symbols
///
/// `#define` and other preprocessor symbols will appear as constants.
/// At present there is no way to do compile-time disablement of code
/// (equivalent of `#ifdef`).
///
/// # Integer types
///
/// For C++ types with a defined size, just go ahead and use `u64`, `i32` etc.
/// For types such as `int` or `unsigned long`, the hope is that you can
/// eventually use `std::os::raw::c_int` oor `std::os::raw::c_ulong` etc.
/// For now, this doesn't quite work: instead you need to wrap these values
/// in a newtype wrapper such as [c_int] or [c_ulong] in this crate.
///
/// # String constants
///
/// Whether from a preprocessor symbol or from a C++ `char*` constant,
/// strings appear as `[u8]` with a null terminator. To get a Rust string,
/// do this:
///
/// ```cpp
/// #define BOB "Hello"
/// ```
///
/// ```
/// # mod ffi { pub static BOB: [u8; 6] = [72u8, 101u8, 108u8, 108u8, 111u8, 0u8]; }
/// assert_eq!(std::str::from_utf8(&ffi::BOB).unwrap().trim_end_matches(char::from(0)), "Hello");
/// ```
///
/// # Namespaces
///
/// The C++ namespace structure is reflected in mods within the generated
/// ffi mod. However, at present there is an internal limitation that
/// autocxx can't handle multiple symbols with the same identifier, even
/// if they're in different namespaces. This will be fixed in future.
///
/// # Overloads - and identifiers ending in digits
///
/// C++ allows function overloads; Rust doesn't. `autocxx` follows the lead
/// of `bindgen` here and generating overloads as `func`, `func1`, `func2` etc.
///
/// # C++ classes - why do I get warnings?
///
/// autocxx is not currently able to distinguish a C++ struct from a C++ class.
/// It currently assumes they're all structs. This results in warnings
/// from most compilers, but could cause actual binary mismatches
/// on some ABIs. This is a temporary known limitation.
///
/// # Forward declarations
///
/// A type which is incomplete in the C++ headers (i.e. represented only by a forward
/// declaration) can't be held in a `UniquePtr` within Rust (because Rust can't know
/// if it has a destructor that will need to be called if the object is `Drop`ped.)
/// Naturally, such an object can't be passed by value either; it can still be
/// referenced in Rust references.
///
/// # Generic types
///
/// If you're using one of the generic types which is supported natively by cxx,
/// e.g. `std::unique_ptr`, it should work as you expect. For other generic types,
/// we synthesize a concrete Rust type, corresponding to a C++ typedef, for each
/// concrete instantiation of the type. Such generated types are always opaque,
/// and never have methods attached. That's therefore enough to pass them
/// between return types and parameters of other functions within `UniquePtr`s
/// but not really enough to do anything else with these types just yet. Hopefully,
/// this will be improved in future. At present such types have a name
/// `AutocxxConcrete{n}` but this may change in future.
#[macro_export]
macro_rules! include_cpp {
    (
        $(#$include:ident $lit:literal)*
        $($mac:ident!($($arg:tt)*))*
    ) => {
        $($crate::$include!{__docs})*
        $($crate::$mac!{__docs})*
        $crate::include_cpp_impl! {
            $(#include $lit)*
            $($mac!($($arg)*))*
        }
    };
}

/// Include a C++ header. A directive to be included inside
/// [include_cpp] - see [include_cpp] for details
#[macro_export]
macro_rules! include {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate Rust bindings for the given C++ type or function.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
/// See also [generate_pod].
#[macro_export]
macro_rules! generate {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate as "plain old data".
/// Generate Rust bindings for the given C++ type such that
/// it can be passed and owned by value in Rust. This only works
/// for C++ types which have trivial move constructors and no
/// destructor - you'll encounter a compile error otherwise.
/// If your type doesn't match that description, use [generate]
/// instead, and own the type using [UniquePtr][autocxx_engine::cxx::UniquePtr].
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! generate_pod {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Skip the normal generation of a `make_string` function
/// and other utilities which we might generate normally.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! exclude_utilities {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Specify that a struct (or other type) is nested within
/// some outer type. autocxx can't currently determine
/// this itself; it's hoped that this is a temporary restriction
/// and that the need for this directive will evaporate soon.
/// Meanwhile, specify two arguments - first the path to the
/// type without any nesting; and secondly the path with nesting.
/// So for instance for a situation like
/// ```cpp
/// namespace A {
///   struct B {
///     struct C {
///       uint32_t b;
///     }
///     uint32_t a;
///   }
/// ```
/// specify
/// `nested_type("A::C", "A::B::C")`
///
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! nested_type {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Entirely block some type from appearing in the generated
/// code. This can be useful if there is a type which is not
/// understood by bindgen or autocxx, and incorrect code is
/// otherwise generated.
/// This is 'greedy' in the sense that any functions/methods
/// which take or return such a type will _also_ be blocked.
///
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! block {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Specifies a global safety policy for functions generated
/// from these headers. By default (without such a `safety!`
/// directive) all such functions are marked as `unsafe` and
/// therefore can only be called within an `unsafe {}` block
/// or some `unsafe` function which you create.
///
/// Alternatively, by specifying a `safety!` block you can
/// declare that all generated functions are in fact safe.
/// Specifically, you'd specify:
/// `safety!(unsafe)`
/// or
/// `safety!(unsafe_ffi)`
/// These two options are functionally identical. If you're
/// unsure, simply use `unsafe`. The reason for the
/// latter option is if you have code review policies which
/// might want to give a different level of scrutiny to
/// C++ interop as opposed to other types of unsafe Rust code.
/// Maybe in your organization, C++ interop is less scary than
/// a low-level Rust data structure using pointer manipulation.
/// Or maybe it's more scary. Either way, using `unsafe` for
/// the data structure and using `unsafe_ffi` for the C++
/// interop allows you to apply different linting tools and
/// policies to the different options.
///
/// Irrespective, C++ code is of course unsafe. It's worth
/// noting that use of C++ can cause unexpected unsafety at
/// a distance in faraway Rust code. As with any use of the
/// `unsafe` keyword in Rust, *you the human* are declaring
/// that you've analyzed all possible ways that the code
/// can be used and you are guaranteeing to the compiler that
/// no badness can occur. Good luck.
#[macro_export]
macro_rules! safety {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

#[doc(hidden)]
#[macro_export]
macro_rules! usage {
    (__docs) => {};
    ($($tt:tt)*) => {
        compile_error! {r#"usage:  include_cpp! {
                   #include "path/to/header.h"
                   generate!(...)
                   generate_pod!(...)
               }
"#}
    };
}

#[doc(hidden)]
pub use autocxx_macro::include_cpp_impl;

macro_rules! ctype_wrapper {
    ($r:ident, $c:expr) => {
        /// Newtype wrapper for a `$c`
        #[derive(Debug, Eq, Clone, PartialEq, Hash)]
        #[allow(non_camel_case_types)]
        #[repr(transparent)]
        pub struct $r(pub ::std::os::raw::$r);

        unsafe impl autocxx_engine::cxx::ExternType for $r {
            type Id = autocxx_engine::cxx::type_id!($c);
            type Kind = autocxx_engine::cxx::kind::Trivial;
        }
    };
}

ctype_wrapper!(c_ulong, "c_ulong");
ctype_wrapper!(c_long, "c_long");
ctype_wrapper!(c_ushort, "c_ushort");
ctype_wrapper!(c_short, "c_short");
ctype_wrapper!(c_uint, "c_uint");
ctype_wrapper!(c_int, "c_int");
ctype_wrapper!(c_uchar, "c_uchar");
ctype_wrapper!(c_char, "c_char");
<commit_msg>Fixing docs.<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.

// The crazy macro_rules magic in this file is thanks to dtolnay@
// and is a way of attaching rustdoc to each of the possible directives
// within the include_cpp outer macro. None of the directives actually
// do anything - all the magic is handled entirely by
// autocxx_macro::include_cpp_impl.

/// Include some C++ headers in your Rust project.
///
/// This macro allows you to include one or more C++ headers within
/// your Rust code, and call their functions fairly naturally.
///
/// # Examples
///
/// C++ header (`input.h`):
/// ```cpp
/// #include <cstdint>
///
/// uint32_t do_math(uint32_t a);
/// ```
///
/// Rust code:
/// ```
/// # use autocxx_macro::include_cpp_impl as include_cpp;
/// include_cpp!(
/// #   parse_only
///     #include "input.h"
///     generate!("do_math")
///     safety!(unsafe)
/// );
///
/// # mod ffi { pub fn do_math(a: u32) -> u32 { a+3 } }
/// # fn main() {
/// ffi::do_math(3);
/// # }
/// ```
///
/// # Configuring the build
///
/// To build this, you'll need to:
/// * Build the C++ side of the bindings. You'll need to use the `autocxx-gen`
///   crate or the `autocxx-build` crate to process the .rs code into C++ header and
///   implementation files.
/// * Educate the procedural macro about where to find the C++ headers. Set the
///   `AUTOCXX_INC` environment variable to a list of directories to search.
///   If you use `autocxx-build`, this happens automatically.

///
/// # Syntax
///
/// Within the brackets of the `include_cxx!(...)` macro, you should provide
/// a list of at least the following:
///
/// * `#include "cpp_header.h"`: a header filename to parse and include
/// * `generate!("type_or_function_name")`: a type or function name whose declaration
///   should be made available to C++.
/// * Possibly, `safety!(unsafe)` - see discussion of [unsafe] later.
///
/// Other directives are possible as documented in this crate.
///
/// # How to generate structs
///
/// All C++ types can be owned within a [UniquePtr][autocxx_engine::cxx::UniquePtr]
/// within Rust. To let this be possible, simply pass the names of these
/// types within [generate] (or just [generate] any function which requires these types).
///
/// However, only _some_ C++ `struct`s can be owned _by value_ within Rust. Those
/// types must be freely byte-copyable, because Rust is free to do that at
/// any time. If you believe your `struct` meets those criteria, you can
/// use [generate_pod] instead.
///
/// Use [generate] under normal circumstances, but [generate_pod] only for structs
/// where you absolutely do need to pass them truly by value and have direct field access.
///
/// This doesn't just make a difference to the generated code for the type;
/// it also makes a difference to any functions which take or return that type.
/// If there's a C++ function which takes a struct by value, but that struct
/// is not declared as POD-safe, then we'll generate wrapper functions to move
/// that type into and out of [UniquePtr][autocxx_engine::cxx::UniquePtr]s.
///
/// # Generated code
///
/// You will find that this macro expands to the equivalent of:
///
/// ```no_run
/// mod ffi {
///     pub fn do_math(a: u32) -> u32
/// #   { a+3 }
///     pub const kMyCxxConst: i32 = 3;
///     pub const MY_PREPROCESSOR_DEFINITION: i64 = 3i64;
/// }
/// ```
///
/// # Built-in types
///
/// The generated code uses `cxx` for interop: see that crate for many important
/// considerations including safety and the list of built-in types, for example
/// [UniquePtr][autocxx_engine::cxx::UniquePtr] and
/// [CxxString][autocxx_engine::cxx::CxxString].
///
/// # Making strings
///
/// Unless you use [exclude_utilities], you will find a trait called
/// `ffi::ToCppString` which you can use to convert any Rust string into a C++
/// `std::unique_ptr<std::string>` like this:
///
/// ```ignore
/// use ffi::ToCpp;
/// let unique_ptr_to_cxx_string = "my_string".to_cpp();
/// ```
///
/// # Making other C++ types
///
/// Types gain a `make_unique` associated function. At present they only
/// gain this if they have an explicit C++ constructor; this is a limitation
/// which should be resolved in future.
/// This will (of course) return a `UniquePtr` containing that type.
///
/// # Preprocessor symbols
///
/// `#define` and other preprocessor symbols will appear as constants.
/// At present there is no way to do compile-time disablement of code
/// (equivalent of `#ifdef`).
///
/// # Integer types
///
/// For C++ types with a defined size, just go ahead and use `u64`, `i32` etc.
/// For types such as `int` or `unsigned long`, the hope is that you can
/// eventually use `std::os::raw::c_int` oor `std::os::raw::c_ulong` etc.
/// For now, this doesn't quite work: instead you need to wrap these values
/// in a newtype wrapper such as [c_int] or [c_ulong] in this crate.
///
/// # String constants
///
/// Whether from a preprocessor symbol or from a C++ `char*` constant,
/// strings appear as `[u8]` with a null terminator. To get a Rust string,
/// do this:
///
/// ```cpp
/// #define BOB "Hello"
/// ```
///
/// ```
/// # mod ffi { pub static BOB: [u8; 6] = [72u8, 101u8, 108u8, 108u8, 111u8, 0u8]; }
/// assert_eq!(std::str::from_utf8(&ffi::BOB).unwrap().trim_end_matches(char::from(0)), "Hello");
/// ```
///
/// # Namespaces
///
/// The C++ namespace structure is reflected in mods within the generated
/// ffi mod. However, at present there is an internal limitation that
/// autocxx can't handle multiple symbols with the same identifier, even
/// if they're in different namespaces. This will be fixed in future.
///
/// # Overloads - and identifiers ending in digits
///
/// C++ allows function overloads; Rust doesn't. `autocxx` follows the lead
/// of `bindgen` here and generating overloads as `func`, `func1`, `func2` etc.
///
/// # C++ classes - why do I get warnings?
///
/// autocxx is not currently able to distinguish a C++ struct from a C++ class.
/// It currently assumes they're all structs. This results in warnings
/// from most compilers, but could cause actual binary mismatches
/// on some ABIs. This is a temporary known limitation.
///
/// # Forward declarations
///
/// A type which is incomplete in the C++ headers (i.e. represented only by a forward
/// declaration) can't be held in a `UniquePtr` within Rust (because Rust can't know
/// if it has a destructor that will need to be called if the object is `Drop`ped.)
/// Naturally, such an object can't be passed by value either; it can still be
/// referenced in Rust references.
///
/// # Generic types
///
/// If you're using one of the generic types which is supported natively by cxx,
/// e.g. `std::unique_ptr`, it should work as you expect. For other generic types,
/// we synthesize a concrete Rust type, corresponding to a C++ typedef, for each
/// concrete instantiation of the type. Such generated types are always opaque,
/// and never have methods attached. That's therefore enough to pass them
/// between return types and parameters of other functions within `UniquePtr`s
/// but not really enough to do anything else with these types just yet. Hopefully,
/// this will be improved in future. At present such types have a name
/// `AutocxxConcrete{n}` but this may change in future.
#[macro_export]
macro_rules! include_cpp {
    (
        $(#$include:ident $lit:literal)*
        $($mac:ident!($($arg:tt)*))*
    ) => {
        $($crate::$include!{__docs})*
        $($crate::$mac!{__docs})*
        $crate::include_cpp_impl! {
            $(#include $lit)*
            $($mac!($($arg)*))*
        }
    };
}

/// Include a C++ header. A directive to be included inside
/// [include_cpp] - see [include_cpp] for details
#[macro_export]
macro_rules! include {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate Rust bindings for the given C++ type or function.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
/// See also [generate_pod].
#[macro_export]
macro_rules! generate {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Generate as "plain old data".
/// Generate Rust bindings for the given C++ type such that
/// it can be passed and owned by value in Rust. This only works
/// for C++ types which have trivial move constructors and no
/// destructor - you'll encounter a compile error otherwise.
/// If your type doesn't match that description, use [generate]
/// instead, and own the type using [UniquePtr][autocxx_engine::cxx::UniquePtr].
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! generate_pod {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Skip the normal generation of a `make_string` function
/// and other utilities which we might generate normally.
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! exclude_utilities {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Specify that a struct (or other type) is nested within
/// some outer type. autocxx can't currently determine
/// this itself; it's hoped that this is a temporary restriction
/// and that the need for this directive will evaporate soon.
/// Meanwhile, specify two arguments - first the path to the
/// type without any nesting; and secondly the path with nesting.
/// So for instance for a situation like
/// ```cpp
/// namespace A {
///   struct B {
///     struct C {
///       uint32_t b;
///     }
///     uint32_t a;
///   }
/// ```
/// specify
/// `nested_type("A::C", "A::B::C")`
///
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! nested_type {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Entirely block some type from appearing in the generated
/// code. This can be useful if there is a type which is not
/// understood by bindgen or autocxx, and incorrect code is
/// otherwise generated.
/// This is 'greedy' in the sense that any functions/methods
/// which take or return such a type will _also_ be blocked.
///
/// A directive to be included inside
/// [include_cpp] - see [include_cpp] for general information.
#[macro_export]
macro_rules! block {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

/// Specifies a global safety policy for functions generated
/// from these headers. By default (without such a `safety!`
/// directive) all such functions are marked as `unsafe` and
/// therefore can only be called within an `unsafe {}` block
/// or some `unsafe` function which you create.
///
/// Alternatively, by specifying a `safety!` block you can
/// declare that all generated functions are in fact safe.
/// Specifically, you'd specify:
/// `safety!(unsafe)`
/// or
/// `safety!(unsafe_ffi)`
/// These two options are functionally identical. If you're
/// unsure, simply use `unsafe`. The reason for the
/// latter option is if you have code review policies which
/// might want to give a different level of scrutiny to
/// C++ interop as opposed to other types of unsafe Rust code.
/// Maybe in your organization, C++ interop is less scary than
/// a low-level Rust data structure using pointer manipulation.
/// Or maybe it's more scary. Either way, using `unsafe` for
/// the data structure and using `unsafe_ffi` for the C++
/// interop allows you to apply different linting tools and
/// policies to the different options.
///
/// Irrespective, C++ code is of course unsafe. It's worth
/// noting that use of C++ can cause unexpected unsafety at
/// a distance in faraway Rust code. As with any use of the
/// `unsafe` keyword in Rust, *you the human* are declaring
/// that you've analyzed all possible ways that the code
/// can be used and you are guaranteeing to the compiler that
/// no badness can occur. Good luck.
#[macro_export]
macro_rules! safety {
    ($($tt:tt)*) => { $crate::usage!{$($tt)*} };
}

#[doc(hidden)]
#[macro_export]
macro_rules! usage {
    (__docs) => {};
    ($($tt:tt)*) => {
        compile_error! {r#"usage:  include_cpp! {
                   #include "path/to/header.h"
                   generate!(...)
                   generate_pod!(...)
               }
"#}
    };
}

#[doc(hidden)]
pub use autocxx_macro::include_cpp_impl;

macro_rules! ctype_wrapper {
    ($r:ident, $c:expr) => {
        /// Newtype wrapper for a `$c`
        #[derive(Debug, Eq, Clone, PartialEq, Hash)]
        #[allow(non_camel_case_types)]
        #[repr(transparent)]
        pub struct $r(pub ::std::os::raw::$r);

        unsafe impl autocxx_engine::cxx::ExternType for $r {
            type Id = autocxx_engine::cxx::type_id!($c);
            type Kind = autocxx_engine::cxx::kind::Trivial;
        }
    };
}

ctype_wrapper!(c_ulong, "c_ulong");
ctype_wrapper!(c_long, "c_long");
ctype_wrapper!(c_ushort, "c_ushort");
ctype_wrapper!(c_short, "c_short");
ctype_wrapper!(c_uint, "c_uint");
ctype_wrapper!(c_int, "c_int");
ctype_wrapper!(c_uchar, "c_uchar");
ctype_wrapper!(c_char, "c_char");
<|endoftext|>


<commit_before>#![cfg_attr(test, feature(test))]

extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, Read, Seek, SeekFrom, BufRead, BufReader};
use std::fs::File;
use std::cell::RefCell;

pub mod errors;
use errors::ReadError;

pub struct BigArchive<T: Read + Seek> {
    pub format: Format,
    pub size: u32,

    _buf_reader: RefCell<BufReader<T>>,
    _entries: HashMap<String, BigEntry>,
}

impl BigArchive<File> {
    pub fn new_from_path(path: &str) -> Result<Self, ReadError> {
        let f = try!(File::open(&path));
        let br = BufReader::new(f);
        Ok(try!(BigArchive::new(br)))
    }
}

impl<T: Read + Seek> BigArchive<T> {
    pub fn new(mut data: BufReader<T>) -> Result<Self, ReadError> {
        let format = read_format(&mut data).expect("Failed to read format");

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownArchiveFormat(bytes));
        }

        let size = try!(data.read_u32::<LittleEndian>());
        let size = invert_endianness(size);

        let num_entries = try!(data.read_u32::<LittleEndian>());
        let num_entries = invert_endianness(num_entries);

        // Offset to the first entry, I think.
        let _ = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let offset = try!(data.read_u32::<LittleEndian>());
            let offset = invert_endianness(offset);

            let size = try!(data.read_u32::<LittleEndian>());
            let size = invert_endianness(size);

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", i + 1));

            // Remove the trailing \0
            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _buf_reader: RefCell::new(data),
            _entries: entries,
        })
    }

    /// TODO: Don't return owned data, instead give the caller back a slice
    pub fn read_entry(&self, entry_name: &str) -> Option<Vec<u8>> {
        if let Some(entry) = self._entries.get(entry_name) {
            let br = &mut self._buf_reader.borrow_mut();

            if br.seek(SeekFrom::Start((*entry).offset as u64)).is_err() {
                return None;
            }

            let mut buf = vec![0; entry.size as usize];
            if br.read_exact(&mut buf).is_err() {
                return None;
            }

            Some(buf)
        } else {
            None
        }
    }

    pub fn contains(&self, entry_name: &str) -> bool {
        self._entries.contains_key(entry_name)
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGF" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

fn invert_endianness(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests_bytes {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");
    use std::io::{BufReader, Cursor};
    use super::{Format, BigArchive};

    #[test]
    fn is_big4() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}

#[cfg(test)]
mod tests_file {
    use super::{Format, BigArchive};
    const ARCHIVE_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/test.big");

    #[test]
    fn is_big4() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}
<commit_msg>Use try! instead of Result::expect in BigArchive::new<commit_after>#![cfg_attr(test, feature(test))]

extern crate byteorder;
use byteorder::{LittleEndian, ReadBytesExt};

use std::collections::HashMap;
use std::io::{self, Read, Seek, SeekFrom, BufRead, BufReader};
use std::fs::File;
use std::cell::RefCell;

pub mod errors;
use errors::ReadError;

pub struct BigArchive<T: Read + Seek> {
    pub format: Format,
    pub size: u32,

    _buf_reader: RefCell<BufReader<T>>,
    _entries: HashMap<String, BigEntry>,
}

impl BigArchive<File> {
    pub fn new_from_path(path: &str) -> Result<Self, ReadError> {
        let f = try!(File::open(&path));
        let br = BufReader::new(f);
        Ok(try!(BigArchive::new(br)))
    }
}

impl<T: Read + Seek> BigArchive<T> {
    pub fn new(mut data: BufReader<T>) -> Result<Self, ReadError> {
        let format = try!(read_format(&mut data));

        if let Format::Unknown(bytes) = format {
            return Err(ReadError::UnknownArchiveFormat(bytes));
        }

        let size = try!(data.read_u32::<LittleEndian>());
        let size = invert_endianness(size);

        let num_entries = try!(data.read_u32::<LittleEndian>());
        let num_entries = invert_endianness(num_entries);

        // Offset to the first entry, I think.
        let _ = data.read_u32::<LittleEndian>();

        let mut entries = HashMap::new();

        for i in 0..num_entries {
            let offset = try!(data.read_u32::<LittleEndian>());
            let offset = invert_endianness(offset);

            let size = try!(data.read_u32::<LittleEndian>());
            let size = invert_endianness(size);

            let mut buf = Vec::new();
            data.read_until(b'\0', &mut buf)
                .expect(&format!("Failed to read name for entry {}", i + 1));

            // Remove the trailing \0
            let name = String::from_utf8_lossy(&buf[..buf.len() - 1]);

            let entry = BigEntry {
                offset: offset,
                size: size,
                name: name.to_string(),
            };

            entries.insert(entry.name.clone(), entry);
        }

        Ok(BigArchive {
            format: format,
            size: size,
            _buf_reader: RefCell::new(data),
            _entries: entries,
        })
    }

    /// TODO: Don't return owned data, instead give the caller back a slice
    pub fn read_entry(&self, entry_name: &str) -> Option<Vec<u8>> {
        if let Some(entry) = self._entries.get(entry_name) {
            let br = &mut self._buf_reader.borrow_mut();

            if br.seek(SeekFrom::Start((*entry).offset as u64)).is_err() {
                return None;
            }

            let mut buf = vec![0; entry.size as usize];
            if br.read_exact(&mut buf).is_err() {
                return None;
            }

            Some(buf)
        } else {
            None
        }
    }

    pub fn contains(&self, entry_name: &str) -> bool {
        self._entries.contains_key(entry_name)
    }

    pub fn get_entry(&self, entry_name: &str) -> Option<&BigEntry> {
        self._entries.get(entry_name)
    }

    pub fn get_entry_mut(&mut self, entry_name: &str) -> Option<&mut BigEntry> {
        self._entries.get_mut(entry_name)
    }

    pub fn get_all_entry_names(&self) -> std::collections::hash_map::Keys<String, BigEntry> {
        self._entries.keys()
    }
}

#[derive(Debug)]
pub struct BigEntry {
    pub offset: u32,
    pub size: u32,
    pub name: String,
}

#[derive(Debug, PartialEq)]
pub enum Format {
    Unknown(Vec<u8>),
    Big4,
    BigF,
}

impl<'a> From<&'a mut BufRead> for Format {
    fn from(data: &'a mut BufRead) -> Self {
        let mut buf = [0; 4];
        let _ = data.read_exact(&mut buf);
        match &buf {
            b"BIG4" => Format::Big4,
            b"BIGF" => Format::BigF,
            _ => Format::Unknown(Vec::from(&buf[..])),
        }
    }
}

fn read_format(data: &mut BufRead) -> Result<Format, io::Error> {
    Ok(Format::from(data))
}

fn invert_endianness(v: u32) -> u32 {
    (v << 24) | (v << 8 & 0xff0000) | (v >> 8 & 0xff00) | (v >> 24)
}

#[cfg(test)]
mod tests_bytes {
    const TEST_BYTES: &'static [u8] = include_bytes!("../test.big");
    use std::io::{BufReader, Cursor};
    use super::{Format, BigArchive};

    #[test]
    fn is_big4() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let c = Cursor::new(TEST_BYTES);
        let br = BufReader::new(c);
        let archive = BigArchive::new(br).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}

#[cfg(test)]
mod tests_file {
    use super::{Format, BigArchive};
    const ARCHIVE_PATH: &'static str = concat!(env!("CARGO_MANIFEST_DIR"), "/test.big");

    #[test]
    fn is_big4() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.format, Format::Big4);
    }

    #[test]
    fn has_two_entries() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert_eq!(archive.get_all_entry_names().len(), 2);
    }

    #[test]
    fn contains_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("art/image.txt"));
    }

    #[test]
    fn contains_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        assert!(archive.contains("data/test.ini"));
    }

    #[test]
    fn read_entry_art_slash_image_dot_txt() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("art/image.txt").unwrap();
        assert_eq!(data, vec![98, 108, 97, 98, 108, 98, 97]);
    }

    #[test]
    fn read_entry_data_slash_test_dot_ini() {
        let archive = BigArchive::new_from_path(&ARCHIVE_PATH).unwrap();
        let data = archive.read_entry("data/test.ini").unwrap();
        assert_eq!(data,
                   vec![84, 104, 105, 115, 32, 105, 115, 32, 97, 32, 115, 105, 109, 112, 108,
                        101, 32, 116, 101, 115, 116, 32, 102, 105, 108, 101]);
    }

    mod benches {
        extern crate test;
        use self::test::Bencher;

        #[bench]
        fn is_big4(b: &mut Bencher) {
            b.iter(|| super::is_big4());
        }

        #[bench]
        fn has_two_entries(b: &mut Bencher) {
            b.iter(|| super::has_two_entries());
        }

        #[bench]
        fn contains_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::contains_art_slash_image_dot_txt());
        }

        #[bench]
        fn contains_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::contains_data_slash_test_dot_ini());
        }

        #[bench]
        fn read_entry_art_slash_image_dot_txt(b: &mut Bencher) {
            b.iter(|| super::read_entry_art_slash_image_dot_txt());
        }

        #[bench]
        fn read_entry_data_slash_test_dot_ini(b: &mut Bencher) {
            b.iter(|| super::read_entry_data_slash_test_dot_ini());
        }
    }
}
<|endoftext|>


<commit_before>/*!

Tantivy is a search engine library.

*/

#![feature(binary_heap_extras)]
#![feature(conservative_impl_trait)]
#![cfg_attr(test, feature(test))]
#![cfg_attr(test, feature(step_by))]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
#![feature(conservative_impl_trait)]

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate fst;
extern crate byteorder;
extern crate memmap;
extern crate regex;
extern crate tempfile;
extern crate rustc_serialize;
extern crate atomicwrites;
extern crate tempdir;
extern crate bincode;
extern crate time;
extern crate libc;
extern crate lz4;
extern crate uuid;
extern crate num_cpus;
extern crate combine;
extern crate itertools;
extern crate chan;
extern crate crossbeam;

#[cfg(test)] extern crate test;
#[cfg(test)] extern crate rand;

#[macro_use]
mod macros {
    macro_rules! get(
        ($e:expr) => (match $e { Some(e) => e, None => return None })
    );
}

mod core;
mod compression;
mod fastfield;
mod store;
mod indexer;
mod common;
mod error;

pub use error::{Result, Error};

mod analyzer;
mod datastruct;

pub mod postings;
pub mod query;
pub mod directory;

pub mod collector;
pub mod schema;

pub use directory::Directory;
pub use core::searcher::Searcher;
pub use core::Index;
pub use indexer::IndexWriter;
pub use schema::Term;
pub use schema::Document;
pub use core::SegmentReader;
pub use self::common::TimerTree;

pub use postings::DocSet;
pub use postings::Postings;
pub use postings::SegmentPostingsOption;

/// u32 identifying a document within a segment.
/// Document gets their doc id assigned incrementally,
/// as they are added in the segment.
pub type DocId = u32;

/// f32 the score of a document.
pub type Score = f32;

/// A segment local id identifies a segment.
/// It only makes sense for a given searcher.
pub type SegmentLocalId = u32;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DocAddress(pub SegmentLocalId, pub DocId);

impl DocAddress {
    pub fn segment_ord(&self,) -> SegmentLocalId {
        self.0
    }

    pub fn doc(&self,) -> DocId {
        self.1
    }
}

#[derive(Clone, Copy)]
pub struct ScoredDoc(Score, DocId);

impl ScoredDoc {
    pub fn score(&self,) -> Score {
        self.0
    }
    pub fn doc(&self,) -> DocId {
        self.1
    }
}

#[cfg(test)]
mod tests {

    use collector::TestCollector;
    use query::MultiTermQuery;
    use Index;
    use core::SegmentReader;
    use schema::*;
    use DocSet;
    use Postings;

    #[test]
    fn test_indexing() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_from_tempdir(schema).unwrap();
        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 100_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            assert!(index_writer.commit().is_ok());
        }

    }

    #[test]
    fn test_docfreq() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        {
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            let mut doc = Document::new();
            doc.add_text(text_field, "a b c");
            index_writer.add_document(doc).unwrap();
            index_writer.commit().unwrap();
        }
        {
            let mut index_writer = index.writer_with_num_threads(1, 100_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a a");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let mut index_writer = index.writer_with_num_threads(1, 100_000).unwrap();
            let mut doc = Document::new();
            doc.add_text(text_field, "c");
            index_writer.add_document(doc).unwrap();
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let term_a = Term::from_field_text(text_field, "a");
            assert_eq!(searcher.doc_freq(&term_a), 3);
            let term_b = Term::from_field_text(text_field, "b");
            assert_eq!(searcher.doc_freq(&term_b), 1);
            let term_c = Term::from_field_text(text_field, "c");
            assert_eq!(searcher.doc_freq(&term_c), 2);
            let term_d = Term::from_field_text(text_field, "d");
            assert_eq!(searcher.doc_freq(&term_d), 0);
        }
    }

    #[test]
    fn test_fieldnorm() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        {
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let doc = Document::new();
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {

            let searcher = index.searcher();
            let segment_reader: &SegmentReader = searcher.segment_readers().iter().next().unwrap();
            let fieldnorms_reader = segment_reader.get_fieldnorms_reader(text_field).unwrap();
            assert_eq!(fieldnorms_reader.get(0), 3);
            assert_eq!(fieldnorms_reader.get(1), 0);
            assert_eq!(fieldnorms_reader.get(2), 2);
        }
    }

    #[test]
    fn test_termfreq() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af af af bc bc");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let reader = searcher.segment_reader(0);
            let mut postings = reader.read_postings_all_info(&Term::from_field_text(text_field, "af"));
            assert!(postings.advance());
            assert_eq!(postings.doc(), 0);
            assert_eq!(postings.term_freq(), 3);
            assert!(!postings.advance());
        }
    }

    #[test]
    fn test_searcher() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);

        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 100_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af af af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let get_doc_ids = |terms: Vec<Term>| {
                let query = MultiTermQuery::from(terms);
                let mut collector = TestCollector::new();
                assert!(searcher.search(&query, &mut collector).is_ok());
                collector.docs()
            };
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "a"))),
                    vec!(1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "af"))),
                    vec!(0));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "b"))),
                    vec!(0, 1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "c"))),
                    vec!(1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "d"))),
                    vec!(2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "b"),
                                     Term::from_field_text(text_field, "a"), )),
                    vec!(0, 1, 2));
            }
        }
    }

    #[test]
    fn test_searcher_2() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);

        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 100_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        index.searcher();
    }
}
<commit_msg>Bigger heap in unit testwq<commit_after>/*!

Tantivy is a search engine library.

*/

#![feature(binary_heap_extras)]
#![feature(conservative_impl_trait)]
#![cfg_attr(test, feature(test))]
#![cfg_attr(test, feature(step_by))]
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
#![feature(conservative_impl_trait)]

#[macro_use]
extern crate lazy_static;

#[macro_use]
extern crate fst;
extern crate byteorder;
extern crate memmap;
extern crate regex;
extern crate tempfile;
extern crate rustc_serialize;
extern crate atomicwrites;
extern crate tempdir;
extern crate bincode;
extern crate time;
extern crate libc;
extern crate lz4;
extern crate uuid;
extern crate num_cpus;
extern crate combine;
extern crate itertools;
extern crate chan;
extern crate crossbeam;

#[cfg(test)] extern crate test;
#[cfg(test)] extern crate rand;

#[macro_use]
mod macros {
    macro_rules! get(
        ($e:expr) => (match $e { Some(e) => e, None => return None })
    );
}

mod core;
mod compression;
mod fastfield;
mod store;
mod indexer;
mod common;
mod error;

pub use error::{Result, Error};

mod analyzer;
mod datastruct;

pub mod postings;
pub mod query;
pub mod directory;

pub mod collector;
pub mod schema;

pub use directory::Directory;
pub use core::searcher::Searcher;
pub use core::Index;
pub use indexer::IndexWriter;
pub use schema::Term;
pub use schema::Document;
pub use core::SegmentReader;
pub use self::common::TimerTree;

pub use postings::DocSet;
pub use postings::Postings;
pub use postings::SegmentPostingsOption;

/// u32 identifying a document within a segment.
/// Document gets their doc id assigned incrementally,
/// as they are added in the segment.
pub type DocId = u32;

/// f32 the score of a document.
pub type Score = f32;

/// A segment local id identifies a segment.
/// It only makes sense for a given searcher.
pub type SegmentLocalId = u32;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DocAddress(pub SegmentLocalId, pub DocId);

impl DocAddress {
    pub fn segment_ord(&self,) -> SegmentLocalId {
        self.0
    }

    pub fn doc(&self,) -> DocId {
        self.1
    }
}

#[derive(Clone, Copy)]
pub struct ScoredDoc(Score, DocId);

impl ScoredDoc {
    pub fn score(&self,) -> Score {
        self.0
    }
    pub fn doc(&self,) -> DocId {
        self.1
    }
}

#[cfg(test)]
mod tests {

    use collector::TestCollector;
    use query::MultiTermQuery;
    use Index;
    use core::SegmentReader;
    use schema::*;
    use DocSet;
    use Postings;

    #[test]
    fn test_indexing() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_from_tempdir(schema).unwrap();
        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            assert!(index_writer.commit().is_ok());
        }

    }

    #[test]
    fn test_docfreq() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
        {
            let mut doc = Document::new();
            doc.add_text(text_field, "a b c");
            index_writer.add_document(doc).unwrap();
            index_writer.commit().unwrap();
        }
        {
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a a");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let mut doc = Document::new();
            doc.add_text(text_field, "c");
            index_writer.add_document(doc).unwrap();
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let term_a = Term::from_field_text(text_field, "a");
            assert_eq!(searcher.doc_freq(&term_a), 3);
            let term_b = Term::from_field_text(text_field, "b");
            assert_eq!(searcher.doc_freq(&term_b), 1);
            let term_c = Term::from_field_text(text_field, "c");
            assert_eq!(searcher.doc_freq(&term_c), 2);
            let term_d = Term::from_field_text(text_field, "d");
            assert_eq!(searcher.doc_freq(&term_d), 0);
        }
    }

    #[test]
    fn test_fieldnorm() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let index = Index::create_in_ram(schema_builder.build());
        {
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let doc = Document::new();
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {

            let searcher = index.searcher();
            let segment_reader: &SegmentReader = searcher.segment_readers().iter().next().unwrap();
            let fieldnorms_reader = segment_reader.get_fieldnorms_reader(text_field).unwrap();
            assert_eq!(fieldnorms_reader.get(0), 3);
            assert_eq!(fieldnorms_reader.get(1), 0);
            assert_eq!(fieldnorms_reader.get(2), 2);
        }
    }

    #[test]
    fn test_termfreq() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);
        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af af af bc bc");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let reader = searcher.segment_reader(0);
            let mut postings = reader.read_postings_all_info(&Term::from_field_text(text_field, "af"));
            assert!(postings.advance());
            assert_eq!(postings.doc(), 0);
            assert_eq!(postings.term_freq(), 3);
            assert!(!postings.advance());
        }
    }

    #[test]
    fn test_searcher() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);

        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af af af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        {
            let searcher = index.searcher();
            let get_doc_ids = |terms: Vec<Term>| {
                let query = MultiTermQuery::from(terms);
                let mut collector = TestCollector::new();
                assert!(searcher.search(&query, &mut collector).is_ok());
                collector.docs()
            };
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "a"))),
                    vec!(1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "af"))),
                    vec!(0));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "b"))),
                    vec!(0, 1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "c"))),
                    vec!(1, 2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "d"))),
                    vec!(2));
            }
            {
                assert_eq!(
                    get_doc_ids(vec!(Term::from_field_text(text_field, "b"),
                                     Term::from_field_text(text_field, "a"), )),
                    vec!(0, 1, 2));
            }
        }
    }

    #[test]
    fn test_searcher_2() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", TEXT);
        let schema = schema_builder.build();
        let index = Index::create_in_ram(schema);

        {
            // writing the segment
            let mut index_writer = index.writer_with_num_threads(1, 30_000_000).unwrap();
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "af b");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c");
                index_writer.add_document(doc).unwrap();
            }
            {
                let mut doc = Document::new();
                doc.add_text(text_field, "a b c d");
                index_writer.add_document(doc).unwrap();
            }
            index_writer.commit().unwrap();
        }
        index.searcher();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
//! `Once` that are smaller, faster and more flexible than those in the Rust
//! standard library. It also provides a `ReentrantMutex` type.

#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#![cfg_attr(feature = "nightly", feature(const_atomic_u8_new))]
#![cfg_attr(feature = "nightly", feature(const_atomic_usize_new))]
#![cfg_attr(feature = "nightly", feature(const_cell_new))]
#![cfg_attr(feature = "nightly", feature(const_ptr_null_mut))]
#![cfg_attr(feature = "nightly", feature(const_atomic_ptr_new))]
#![cfg_attr(feature = "nightly", feature(const_unsafe_cell_new))]
#![cfg_attr(feature = "nightly", feature(const_size_of))]
#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#![cfg_attr(feature = "nightly", feature(asm))]

#[cfg(feature = "owning_ref")]
extern crate owning_ref;

extern crate parking_lot_core;

#[cfg(not(feature = "nightly"))]
mod stable;

mod util;
mod elision;
mod raw_mutex;
mod raw_remutex;
mod raw_rwlock;
mod condvar;
mod mutex;
mod remutex;
mod rwlock;
mod once;

#[cfg(feature = "deadlock_detection")]
pub mod deadlock;
#[cfg(not(feature = "deadlock_detection"))]
mod deadlock;

pub use once::{Once, OnceState, ONCE_INIT};
pub use mutex::{Mutex, MutexGuard};
pub use remutex::{ReentrantMutex, ReentrantMutexGuard};
pub use condvar::{Condvar, WaitTimeoutResult};
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard, RwLockUpgradableReadGuard};

#[cfg(feature = "owning_ref")]
use owning_ref::OwningRef;

/// Typedef of an owning reference that uses a `MutexGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type MutexGuardRef<'a, T, U = T> = OwningRef<MutexGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `ReentrantMutexGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type ReentrantMutexGuardRef<'a, T, U = T> = OwningRef<ReentrantMutexGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockReadGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockWriteGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockUpgradableReadGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockUpgradableReadGuardRef<'a, T, U = T> = OwningRef<RwLockUpgradableReadGuard<'a, T>, U>;
<commit_msg>Removed unnecessary feature gates<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and
//! `Once` that are smaller, faster and more flexible than those in the Rust
//! standard library. It also provides a `ReentrantMutex` type.

#![warn(missing_docs)]
#![cfg_attr(feature = "nightly", feature(const_fn))]
#![cfg_attr(feature = "nightly", feature(integer_atomics))]
#![cfg_attr(feature = "nightly", feature(asm))]

#[cfg(feature = "owning_ref")]
extern crate owning_ref;

extern crate parking_lot_core;

#[cfg(not(feature = "nightly"))]
mod stable;

mod util;
mod elision;
mod raw_mutex;
mod raw_remutex;
mod raw_rwlock;
mod condvar;
mod mutex;
mod remutex;
mod rwlock;
mod once;

#[cfg(feature = "deadlock_detection")]
pub mod deadlock;
#[cfg(not(feature = "deadlock_detection"))]
mod deadlock;

pub use once::{Once, OnceState, ONCE_INIT};
pub use mutex::{Mutex, MutexGuard};
pub use remutex::{ReentrantMutex, ReentrantMutexGuard};
pub use condvar::{Condvar, WaitTimeoutResult};
pub use rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard, RwLockUpgradableReadGuard};

#[cfg(feature = "owning_ref")]
use owning_ref::OwningRef;

/// Typedef of an owning reference that uses a `MutexGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type MutexGuardRef<'a, T, U = T> = OwningRef<MutexGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `ReentrantMutexGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type ReentrantMutexGuardRef<'a, T, U = T> = OwningRef<ReentrantMutexGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockReadGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockReadGuardRef<'a, T, U = T> = OwningRef<RwLockReadGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockWriteGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockWriteGuardRef<'a, T, U = T> = OwningRef<RwLockWriteGuard<'a, T>, U>;

/// Typedef of an owning reference that uses a `RwLockUpgradableReadGuard` as the owner.
#[cfg(feature = "owning_ref")]
pub type RwLockUpgradableReadGuardRef<'a, T, U = T> = OwningRef<RwLockUpgradableReadGuard<'a, T>, U>;
<|endoftext|>


<commit_before>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/logger")]
#![crate_name = "logger"]
#![license = "MIT"]

//! Request logging middleware for Iron

#[deny(warnings)]

extern crate iron;
extern crate http;
extern crate time;
extern crate term;
extern crate typemap;

use iron::{AfterMiddleware, BeforeMiddleware, IronResult, Request, Response};
use typemap::Assoc;
use time::precise_time_ns;
use term::{Terminal, WriterWrapper, stdout};

use std::io::IoResult;

use format::{Format, FormatText, Str, Method, URI, Status, ResponseTime,
             ConstantColor, FunctionColor, ConstantAttrs, FunctionAttrs};

pub mod format;

/// `Middleware` for logging request and response info to the terminal.
pub struct Logger {
    format: Option<Format>
}

pub struct LoggerBeforeMiddleware;

impl Logger {
    /// Create a pair of `Logger` middlewares with the specified `format`. If a `None` is passed in, uses the default format:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response_time} ms)
    /// ```
    ///
    /// While the returned value can be passed straight to `Chain::link`, consider making the logger `BeforeMiddleware`
    /// the first in your chain and the logger `AfterMiddleware` the last by doing something like this:
    ///
    /// ```ignore
    /// let mut chain = ChainBuilder::new(handler);
    /// let (logger_before, logger_after) = Logger::new(None);
    /// chain.link_before(logger_before);
    /// // link other middlewares here...
    /// chain.link_after(logger_after);
    /// ```
    pub fn new(format: Option<Format>) -> (LoggerBeforeMiddleware, Logger) {
        (LoggerBeforeMiddleware, Logger { format: format })
    }
}

struct StartTime;
impl Assoc<u64> for StartTime {}

impl BeforeMiddleware for LoggerBeforeMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<StartTime, u64>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for Logger {
    fn after(&self, req: &mut Request, res: &mut Response) -> IronResult<()> {
        let entry_time = *req.extensions.find::<StartTime, u64>().unwrap();
        let response_time_ms = (precise_time_ns() - entry_time) as f64 / 1000000.0;
        let Format(format) = self.format.clone().unwrap_or(Format::default());

        let render = |text: &FormatText| {
            match *text {
                Str(ref string) => string.clone(),
                Method => format!("{}", req.method),
                URI => format!("{}", req.url),
                Status => format!("{}", res.status),
                ResponseTime => format!("{} ms", response_time_ms)
            }
        };
        let log = |mut t: Box<Terminal<WriterWrapper> + Send>| -> IoResult<()> {
            for unit in format.iter() {
                match unit.color {
                    ConstantColor(Some(color)) => { try!(t.fg(color)); }
                    ConstantColor(None) => (),
                    FunctionColor(f) => match f(req, res) {
                        Some(color) => { try!(t.fg(color)); }
                        None => ()
                    }
                }
                match unit.attrs {
                    ConstantAttrs(ref attrs) => {
                        for &attr in attrs.iter() {
                            try!(t.attr(attr));
                        }
                    }
                    FunctionAttrs(f) => {
                        for &attr in f(req, res).iter() {
                            try!(t.attr(attr));
                        }
                    }
                }
                try!(write!(t, "{}", render(&unit.text)));
                try!(t.reset());
            }
            try!(writeln!(t, ""));
            Ok(())
        };

        match stdout() {
            Some(terminal) => {
                match log(terminal) {
                    Err(e) => { println!("Error logging to terminal: {}", e); },
                    Ok(_) => ()
                }
            }
            None => { println!("Logger could not open terminal"); }
        }
        Ok(())
    }
}
<commit_msg>(refactor) Use Logger for both before and after.<commit_after>#![doc(html_logo_url = "https://avatars0.githubusercontent.com/u/7853871?s=128", html_favicon_url = "https://avatars0.githubusercontent.com/u/7853871?s=256", html_root_url = "http://ironframework.io/core/logger")]
#![crate_name = "logger"]
#![license = "MIT"]

//! Request logging middleware for Iron

#[deny(warnings)]

extern crate iron;
extern crate http;
extern crate time;
extern crate term;
extern crate typemap;

use iron::{AfterMiddleware, BeforeMiddleware, IronResult, Request, Response};
use typemap::Assoc;
use time::precise_time_ns;
use term::{Terminal, WriterWrapper, stdout};

use std::io::IoResult;

use format::{Format, FormatText, Str, Method, URI, Status, ResponseTime,
             ConstantColor, FunctionColor, ConstantAttrs, FunctionAttrs};

pub mod format;

/// `Middleware` for logging request and response info to the terminal.
pub struct Logger {
    format: Option<Format>
}

impl Logger {
    /// Create a pair of `Logger` middlewares with the specified `format`. If a `None` is passed in, uses the default format:
    ///
    /// ```ignore
    /// {method} {uri} -> {status} ({response_time} ms)
    /// ```
    ///
    /// While the returned value can be passed straight to `Chain::link`, consider making the logger `BeforeMiddleware`
    /// the first in your chain and the logger `AfterMiddleware` the last by doing something like this:
    ///
    /// ```ignore
    /// let mut chain = ChainBuilder::new(handler);
    /// let (logger_before, logger_after) = Logger::new(None);
    /// chain.link_before(logger_before);
    /// // link other middlewares here...
    /// chain.link_after(logger_after);
    /// ```
    pub fn new(format: Option<Format>) -> (Logger, Logger) {
        (Logger { format: format.clone() }, Logger { format: format })
    }
}

struct StartTime;
impl Assoc<u64> for StartTime {}

impl BeforeMiddleware for Logger {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<StartTime, u64>(precise_time_ns());
        Ok(())
    }
}

impl AfterMiddleware for Logger {
    fn after(&self, req: &mut Request, res: &mut Response) -> IronResult<()> {
        let entry_time = *req.extensions.find::<StartTime, u64>().unwrap();
        let response_time_ms = (precise_time_ns() - entry_time) as f64 / 1000000.0;
        let Format(format) = self.format.clone().unwrap_or(Format::default());

        let render = |text: &FormatText| {
            match *text {
                Str(ref string) => string.clone(),
                Method => format!("{}", req.method),
                URI => format!("{}", req.url),
                Status => format!("{}", res.status),
                ResponseTime => format!("{} ms", response_time_ms)
            }
        };
        let log = |mut t: Box<Terminal<WriterWrapper> + Send>| -> IoResult<()> {
            for unit in format.iter() {
                match unit.color {
                    ConstantColor(Some(color)) => { try!(t.fg(color)); }
                    ConstantColor(None) => (),
                    FunctionColor(f) => match f(req, res) {
                        Some(color) => { try!(t.fg(color)); }
                        None => ()
                    }
                }
                match unit.attrs {
                    ConstantAttrs(ref attrs) => {
                        for &attr in attrs.iter() {
                            try!(t.attr(attr));
                        }
                    }
                    FunctionAttrs(f) => {
                        for &attr in f(req, res).iter() {
                            try!(t.attr(attr));
                        }
                    }
                }
                try!(write!(t, "{}", render(&unit.text)));
                try!(t.reset());
            }
            try!(writeln!(t, ""));
            Ok(())
        };

        match stdout() {
            Some(terminal) => {
                match log(terminal) {
                    Err(e) => { println!("Error logging to terminal: {}", e); },
                    Ok(_) => ()
                }
            }
            None => { println!("Logger could not open terminal"); }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>// INSERT_README_VIA_MAKE
extern crate tempfile;

use std::convert::AsRef;
use std::error::Error as ErrorTrait;
use std::fmt;
use std::fs;
use std::io;
use std::path;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

/// Whether to allow overwriting if the target file exists.
#[derive(Clone, Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite,
}

/// Represents an error raised by `AtomicFile.write`.
#[derive(Debug)]
pub enum Error<E> {
    /// The error originated in the library itself, while it was either creating a temporary file
    /// or moving the file into place.
    Internal(io::Error),
    /// The error originated in the user-supplied callback.
    User(E),
}

/// If your callback returns a `std::io::Error`, you can unwrap this type to `std::io::Error`.
impl From<Error<io::Error>> for io::Error {
    fn from(e: Error<io::Error>) -> Self {
        match e {
            Error::Internal(x) => x,
            Error::User(x) => x,
        }
    }
}

impl<E: fmt::Display> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Internal(ref e) => e.fmt(f),
            Error::User(ref e) => e.fmt(f),
        }
    }
}

impl<E: ErrorTrait> ErrorTrait for Error<E> {
    fn cause(&self) -> Option<&dyn ErrorTrait> {
        match *self {
            Error::Internal(ref e) => Some(e),
            Error::User(ref e) => Some(e),
        }
    }
}

fn safe_parent(p: &path::Path) -> Option<&path::Path> {
    match p.parent() {
        None => None,
        Some(x) if x.as_os_str().is_empty() => Some(path::Path::new(".")),
        x => x,
    }
}

/// Create a file and write to it atomically, in a callback.
pub struct AtomicFile {
    /// Path to the final file that is atomically written.
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    /// Directory to which to write the temporary subdirectories.
    tmpdir: path::PathBuf,
}

impl AtomicFile {
    /// Helper for writing to the file at `path` atomically, in write-only mode.
    ///
    /// If `OverwriteBehaviour::DisallowOverwrite` is given,
    /// an `Error::Internal` containing an `std::io::ErrorKind::AlreadyExists`
    /// will be returned from `self.write(...)` if the file exists.
    ///
    /// The temporary file is written to a temporary subdirectory in `.`, to ensure
    /// it’s on the same filesystem (so that the move is atomic).
    pub fn new<P>(path: P, overwrite: OverwriteBehavior) -> Self
    where
        P: AsRef<path::Path>,
    {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(p, overwrite, safe_parent(p).unwrap_or_else(|| path::Path::new(".")))
    }

    /// Like `AtomicFile::new`, but the temporary file is written to a temporary subdirectory in `tmpdir`.
    ///
    /// TODO: does `tmpdir` have to exist?
    pub fn new_with_tmpdir<P, Q>(path: P, overwrite: OverwriteBehavior, tmpdir: Q) -> Self
    where
        P: AsRef<path::Path>,
        Q: AsRef<path::Path>,
    {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf(),
        }
    }

    /// Move the file to `self.path()`. Only call once! Not exposed!
    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path()),
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path {
        &self.path
    }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    ///
    /// The temporary file is written to a randomized temporary subdirectory with prefix `.atomicwrite`.
    pub fn write<T, E, F>(&self, f: F) -> Result<T, Error<E>>
    where
        F: FnOnce(&mut fs::File) -> Result<T, E>,
    {
        let tmpdir = tempfile::Builder::new()
            .prefix(".atomicwrite")
            .tempdir_in(&self.tmpdir)
            .map_err(Error::Internal)?;

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = {
            let mut tmpfile = fs::File::create(&tmppath).map_err(Error::Internal)?;
            let r = f(&mut tmpfile).map_err(Error::User)?;
            tmpfile.sync_all().map_err(Error::Internal)?;
            r
        };
        self.commit(&tmppath).map_err(Error::Internal)?;
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    use super::safe_parent;

    use std::{fs, io, path};

    fn fsync_dir(x: &path::Path) -> io::Result<()> {
        let f = fs::File::open(x)?;
        f.sync_all()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::rename(src, dst)?;

        let dst_directory = safe_parent(dst).unwrap();
        fsync_dir(dst_directory)
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::hard_link(src, dst)?;
        fs::remove_file(src)?;

        let src_directory = safe_parent(src).unwrap();
        let dst_directory = safe_parent(dst).unwrap();
        fsync_dir(dst_directory)?;
        if src_directory != dst_directory {
            fsync_dir(src_directory)?;
        }
        Ok(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;

    use std::ffi::OsStr;
    use std::os::windows::ffi::OsStrExt;
    use std::{io, path};

    macro_rules! call {
        ($e: expr) => {
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::last_os_error())
            }
        };
    }

    fn path_to_windows_str<T: AsRef<OsStr>>(x: T) -> Vec<winapi::shared::ntdef::WCHAR> {
        x.as_ref().encode_wide().chain(Some(0)).collect()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {
            winapi::um::winbase::MoveFileExW(
                path_to_windows_str(src).as_ptr(),
                path_to_windows_str(dst).as_ptr(),
                winapi::um::winbase::MOVEFILE_WRITE_THROUGH
                    | winapi::um::winbase::MOVEFILE_REPLACE_EXISTING,
            )
        })
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {
            winapi::um::winbase::MoveFileExW(
                path_to_windows_str(src).as_ptr(),
                path_to_windows_str(dst).as_ptr(),
                winapi::um::winbase::MOVEFILE_WRITE_THROUGH,
            )
        })
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<commit_msg>cargo fmt<commit_after>// INSERT_README_VIA_MAKE
extern crate tempfile;

use std::convert::AsRef;
use std::error::Error as ErrorTrait;
use std::fmt;
use std::fs;
use std::io;
use std::path;

pub use OverwriteBehavior::{AllowOverwrite, DisallowOverwrite};

/// Whether to allow overwriting if the target file exists.
#[derive(Clone, Copy)]
pub enum OverwriteBehavior {
    /// Overwrite files silently.
    AllowOverwrite,

    /// Don't overwrite files. `AtomicFile.write` will raise errors for such conditions only after
    /// you've already written your data.
    DisallowOverwrite,
}

/// Represents an error raised by `AtomicFile.write`.
#[derive(Debug)]
pub enum Error<E> {
    /// The error originated in the library itself, while it was either creating a temporary file
    /// or moving the file into place.
    Internal(io::Error),
    /// The error originated in the user-supplied callback.
    User(E),
}

/// If your callback returns a `std::io::Error`, you can unwrap this type to `std::io::Error`.
impl From<Error<io::Error>> for io::Error {
    fn from(e: Error<io::Error>) -> Self {
        match e {
            Error::Internal(x) => x,
            Error::User(x) => x,
        }
    }
}

impl<E: fmt::Display> fmt::Display for Error<E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Internal(ref e) => e.fmt(f),
            Error::User(ref e) => e.fmt(f),
        }
    }
}

impl<E: ErrorTrait> ErrorTrait for Error<E> {
    fn cause(&self) -> Option<&dyn ErrorTrait> {
        match *self {
            Error::Internal(ref e) => Some(e),
            Error::User(ref e) => Some(e),
        }
    }
}

fn safe_parent(p: &path::Path) -> Option<&path::Path> {
    match p.parent() {
        None => None,
        Some(x) if x.as_os_str().is_empty() => Some(path::Path::new(".")),
        x => x,
    }
}

/// Create a file and write to it atomically, in a callback.
pub struct AtomicFile {
    /// Path to the final file that is atomically written.
    path: path::PathBuf,
    overwrite: OverwriteBehavior,
    /// Directory to which to write the temporary subdirectories.
    tmpdir: path::PathBuf,
}

impl AtomicFile {
    /// Helper for writing to the file at `path` atomically, in write-only mode.
    ///
    /// If `OverwriteBehaviour::DisallowOverwrite` is given,
    /// an `Error::Internal` containing an `std::io::ErrorKind::AlreadyExists`
    /// will be returned from `self.write(...)` if the file exists.
    ///
    /// The temporary file is written to a temporary subdirectory in `.`, to ensure
    /// it’s on the same filesystem (so that the move is atomic).
    pub fn new<P>(path: P, overwrite: OverwriteBehavior) -> Self
    where
        P: AsRef<path::Path>,
    {
        let p = path.as_ref();
        AtomicFile::new_with_tmpdir(
            p,
            overwrite,
            safe_parent(p).unwrap_or_else(|| path::Path::new(".")),
        )
    }

    /// Like `AtomicFile::new`, but the temporary file is written to a temporary subdirectory in `tmpdir`.
    ///
    /// TODO: does `tmpdir` have to exist?
    pub fn new_with_tmpdir<P, Q>(path: P, overwrite: OverwriteBehavior, tmpdir: Q) -> Self
    where
        P: AsRef<path::Path>,
        Q: AsRef<path::Path>,
    {
        AtomicFile {
            path: path.as_ref().to_path_buf(),
            overwrite,
            tmpdir: tmpdir.as_ref().to_path_buf(),
        }
    }

    /// Move the file to `self.path()`. Only call once! Not exposed!
    fn commit(&self, tmppath: &path::Path) -> io::Result<()> {
        match self.overwrite {
            AllowOverwrite => replace_atomic(tmppath, self.path()),
            DisallowOverwrite => move_atomic(tmppath, self.path()),
        }
    }

    /// Get the target filepath.
    pub fn path(&self) -> &path::Path {
        &self.path
    }

    /// Open a temporary file, call `f` on it (which is supposed to write to it), then move the
    /// file atomically to `self.path`.
    ///
    /// The temporary file is written to a randomized temporary subdirectory with prefix `.atomicwrite`.
    pub fn write<T, E, F>(&self, f: F) -> Result<T, Error<E>>
    where
        F: FnOnce(&mut fs::File) -> Result<T, E>,
    {
        let tmpdir = tempfile::Builder::new()
            .prefix(".atomicwrite")
            .tempdir_in(&self.tmpdir)
            .map_err(Error::Internal)?;

        let tmppath = tmpdir.path().join("tmpfile.tmp");
        let rv = {
            let mut tmpfile = fs::File::create(&tmppath).map_err(Error::Internal)?;
            let r = f(&mut tmpfile).map_err(Error::User)?;
            tmpfile.sync_all().map_err(Error::Internal)?;
            r
        };
        self.commit(&tmppath).map_err(Error::Internal)?;
        Ok(rv)
    }
}

#[cfg(unix)]
mod imp {
    use super::safe_parent;

    use std::{fs, io, path};

    fn fsync_dir(x: &path::Path) -> io::Result<()> {
        let f = fs::File::open(x)?;
        f.sync_all()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::rename(src, dst)?;

        let dst_directory = safe_parent(dst).unwrap();
        fsync_dir(dst_directory)
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        fs::hard_link(src, dst)?;
        fs::remove_file(src)?;

        let src_directory = safe_parent(src).unwrap();
        let dst_directory = safe_parent(dst).unwrap();
        fsync_dir(dst_directory)?;
        if src_directory != dst_directory {
            fsync_dir(src_directory)?;
        }
        Ok(())
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;

    use std::ffi::OsStr;
    use std::os::windows::ffi::OsStrExt;
    use std::{io, path};

    macro_rules! call {
        ($e: expr) => {
            if $e != 0 {
                Ok(())
            } else {
                Err(io::Error::last_os_error())
            }
        };
    }

    fn path_to_windows_str<T: AsRef<OsStr>>(x: T) -> Vec<winapi::shared::ntdef::WCHAR> {
        x.as_ref().encode_wide().chain(Some(0)).collect()
    }

    pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {
            winapi::um::winbase::MoveFileExW(
                path_to_windows_str(src).as_ptr(),
                path_to_windows_str(dst).as_ptr(),
                winapi::um::winbase::MOVEFILE_WRITE_THROUGH
                    | winapi::um::winbase::MOVEFILE_REPLACE_EXISTING,
            )
        })
    }

    pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
        call!(unsafe {
            winapi::um::winbase::MoveFileExW(
                path_to_windows_str(src).as_ptr(),
                path_to_windows_str(dst).as_ptr(),
                winapi::um::winbase::MOVEFILE_WRITE_THROUGH,
            )
        })
    }
}

/// Move `src` to `dst`. If `dst` exists, it will be silently overwritten.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn replace_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::replace_atomic(src, dst)
}

/// Move `src` to `dst`. An error will be returned if `dst` exists.
///
/// Both paths must reside on the same filesystem for the operation to be atomic.
pub fn move_atomic(src: &path::Path, dst: &path::Path) -> io::Result<()> {
    imp::move_atomic(src, dst)
}
<|endoftext|>