<commit_before>/* Copyright 2017 Christopher Bacher
 *
 * 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
 *
 * http://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.
 */

//! Galvanic-assert: Matcher-based assertions for easier testing
//! ============================================================
//! This crate provides a new assertion macros (`assert_that!`, `expect_that!`, `get_expectation_for!`) based on **matching predicates** (matchers) to
//!
//!  * make **writing** asserts easier
//!  * make **reading** asserts comprehendable
//!  * easily **extend** the assertion framework
//!  * provide a large list **common matchers**
//!  * integrate with **galvanic-test** and **galvanic-mock** (both still in development ... stay tuned!)
//!  * be used with your favourite test framework
//!
//! The crate will be part of **galvanic**---a complete test framework for **Rust**.

use std::fmt::{Debug, Display, Formatter, Result as FormatResult};

/// States that the asserted values satisfies the required properties of the supplied `Matcher`.
///
/// The postulated assertion is verfied immediately and panics if it is not satisfied.
/// The macro comes in three different forms:
///
///  1. Assert that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     assert_that!(EXPRESSION);
///     assert_that!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Assert that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult`.
///
///     ```rust,ignore
///     assert_that!(&1, eq(1));
///     assert_that!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Assert that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     assert_that!(panic!("panic"), panics);
///     assert_that!(1+1, does not panic);
///     ```
#[macro_export]
macro_rules! assert_that {
    ( $actual: expr, panics ) => {{
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_ok() {
            panic!("\nFailed assertion; expected expression to panic")
        }
    }};
    ( $actual: expr, does not panic ) => {
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_err() {
            panic!("\nFailed assertion; expression panicked unexpectantly")
        }
    };
    ( $actual: expr) => {{
        if !$actual {
            panic!("\nFailed assertion; '{}' is not true", stringify!($actual));
        }
    }};
    ( $actual: expr , otherwise $reason: expr ) => {{
        if !$actual {
            panic!("\nFailed assertion; expression '{}' is not true,\n    Because: {}",
                   stringify!($actual), $reason
            );
        }
    }};
    ( $actual: expr, $matcher: expr ) => {{
        //use std::borrow::Borrow;
        // store the actual value to borrow it
        let value = $actual;
        // use borrow to obtain a reference of type &T (either from a value of type T or of &T itself---the beauty of the Borrow)
        //let ref_to_value: &_ = value.borrow();
        // store matcher so it's dropped before the actual value (reverse order of declaration)
        let m = $matcher;
        match m.check(value) {
            MatchResult::Matched { .. } => { },
            MatchResult::Failed { name, reason } => {
                panic!("\nFailed assertion of matcher: {}\n{}", name, reason)
            }
        }
    }};
}

/// States that the asserted values satisfies the required properties of the supplied `Matcher`
/// and returns an `Expectation` object to inspect the results at a later time.
///
/// The postulated assertion is verfied immediately,
/// but the returned `Expectation` defers a potential panic either until `Expectation::verify` is called
/// or the `Expectation` object is dropped.
/// It is safe for multiple expectations to fail the assertion code will prevent nested panics.
///
/// The macro comes in three different forms:
///
///  1. Expect that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(EXPRESSION);
///     let e2 = get_expectation_for!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Expect that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult`.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(&1, eq(1));
///     let e2 = get_expectation_for!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Expect that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(panic!("panic"), panics);
///     let e2 = get_expectation_for!(&1+1, does not panic);
///     ```
///
/// An expectation can be verfied manually
///
/// ```rust,ignore
/// let e1 = get_expectation_for!(&1+1, equal_to(0));
/// let e2 = get_expectation_for!(&1+1, less_than(4)); // is executed
/// e1.verify();
/// let e3 = get_expectation_for!(&1+1, panics); // is never executed as e1 panics
/// ```
/// or is automatically verfied on drop.
///
/// ```rust,ignore
/// {
///     let e1 = get_expectation_for!(&1+1, equal_to(0));
///     let e2 = get_expectation_for!(&1+1, less_than(4)); // is executed
/// }
/// let e3 = get_expectation_for!(1+1, panics); // is never executed as e1 panics
/// ```
#[macro_export]
macro_rules! get_expectation_for {
    ( $actual: expr, panics ) => {{
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_ok() {
            let assertion = format!("'{}, panics'", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                "Expected expression to panic".to_string()
            )
        } else {
            Expectation::satisfied()
        }
    }};
    ( $actual: expr, does not panic ) => {{
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_err() {
            let assertion = format!("'{}, does not panic'", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                "Expression panicked unexpectantly".to_string()
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr) => {{
        if !$actual {
            let assertion = format!("'{}' is true", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                format!("'{}' is not true", stringify!($actual))
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr , otherwise $reason: expr ) => {{
        if !$actual {
            let assertion = format!("'{}' is true", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                format!("'{}' is not true,\n\tBecause: {}",
                                        stringify!($actual), $reason)
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr, $matcher: expr ) => {{
        let value = $actual;
        let m = $matcher;
        match m.check(value) {
            MatchResult::Matched { .. } => { Expectation::satisfied() },
            MatchResult::Failed { name, reason } => {
                let assertion = format!("'{}' matches '{}'", stringify!($actual), stringify!($matcher));
                Expectation::failed(assertion, file!().to_string(), line!(),
                                    format!("Failed assertion of matcher: {}\n{}", name, reason)
                )
            }
        }
    }};
}

/// States that the asserted values satisfies the required properties of the supplied `Matcher`
/// but waits until the end of the block to inspect the results.
///
/// The postulated assertion is verfied immediately,
/// but a potential panic is deferred until the end of the block wherein the expectation is stated.
/// It is safe for multiple expectations to fail.
/// The assertion code will prevent nested panics.
///
/// The macro comes in three different forms:
///
///  1. Expect that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     expect_that!(EXPRESSION);
///     expect_that!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Expect that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult
///
///     ```rust,ignore
///     expect_that!(&1, eq(1));
///     expect_that!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Expect that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     expect_that!(panic!("panic"), panics);
///     expect_that!(1+1, does not panic);
///     ```
///
/// An expectation is verified at the end of the block it is stated in:
///
/// ```rust,ignore
/// {
///     expect_that!(&1+1, equal_to(0));
///     expect_that!(&1+1, less_than(4)); // is executed
/// }
/// expect_that!(1+1, panics); // is never executed as e1 panics
/// ```
#[macro_export]
macro_rules! expect_that {
    ( $actual: expr, panics ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, panics); };
    ( $actual: expr, does not panic ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, does not panic); };
    ( $actual: expr) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual); };
    ( $actual: expr , otherwise $reason: expr ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, otherwise $reason); };
    ( $actual: expr, $matcher: expr ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, $matcher); };
}

/// The trait which has to be implemented by all matchers.
pub trait Matcher<'a, T:'a> {
    /// Checks the passed value if it satisfies the `Matcher`.
    ///
    /// Values are always taken as immutable reference as the actual value shouldn't be changed by the matcher.
    fn check(&self, actual: &'a T) -> MatchResult;
}

/// A closures can be used as a `Matcher`.
///
/// The closure must be repeatably callable in case that the matcher is combined with another matcher.
impl<'a, T:'a, F> Matcher<'a,T> for F
where F: Fn(&'a T) -> MatchResult + ?Sized {
    fn check(&self, actual: &'a T) -> MatchResult {
        self(actual)
    }
}

/// The return type of any `Machter`
pub enum MatchResult {
    /// Indicates that the `Matcher` matched the value under inspection.
    Matched {
        /// The `name` of the `Matcher`
        name: String
    },
    /// Indicates that the `Matcher` failed to match the value under inspection.
    Failed {
        /// The `name` of the `Matcher`
        name: String,
        /// The `reason` why the `Matcher` failed
        reason: String
    }
}

/// A builder for creating `MatchResult`s.
///
/// Create a new builder with `new()` or `for_()`
/// and finalize it either with `matched()`, `failed_because()`, or `failed_comparison()`.
pub struct MatchResultBuilder {
    matcher_name: String
}

impl MatchResultBuilder {
    /// Creates a `MatchResultBuilder` for an anonymous `Matcher`.
    pub fn new() -> MatchResultBuilder {
        MatchResultBuilder {
            matcher_name: "_unknown_".to_owned()
        }
    }

    /// Creates `MatchResultBuilder` for a `Matcher` with the given `name`
    pub fn for_(name: &str) -> MatchResultBuilder {
        MatchResultBuilder {
            matcher_name: name.to_owned()
        }
    }

    /// Finalzes the builder indicating that the `Matcher` matched the inspected value.
    pub fn matched(self) -> MatchResult {
        MatchResult::Matched { name: self.matcher_name }
    }

    /// Finalzes the builder indicating that the `Matcher` failed to the inspected value.
    ///
    /// The `reason` should give a short indication why the matcher failed.
    pub fn failed_because(self, reason: &str) -> MatchResult {
        MatchResult::Failed {
            name: self.matcher_name,
            reason: format!("  Because: {}", reason)
        }
    }

    /// Finalzes the builder indicating that the `Matcher` failed to the inspected value.
    ///
    /// The `actual` and `expected` value are used the generate a useful error message.
    pub fn failed_comparison<T: Debug>(self, actual: &T, expected: &T) -> MatchResult {
        MatchResult::Failed {
            name: self.matcher_name,
            reason: format!("  Expected: {:?}\n  Got: {:?}", expected, actual)
        }
    }
}

/// The result of a deferred assertion.
///
///
pub enum Expectation {
    Failed {
        /// A representation of the failed assertion.
        assertion: String,
        /// The file where the expection has been created.
        file: String,
        /// The source code line where the expectation has been created.
        line: u32,
        /// The reason why the expectation has not been met.
        error_msg: String
    },
    Satisfied
}

impl Expectation {
    /// Creates a failed `Expectation`
    pub fn failed(assertion:String, file: String, line: u32, error_msg: String) -> Expectation {
        Expectation::Failed {
            assertion: assertion,
            file: file,
            line: line,
            error_msg: error_msg
        }
    }

    /// Create a satisfied `Expectation`
    pub fn satisfied() -> Expectation {
        Expectation::Satisfied
    }

    /// Verifies if the asseration given by the `Expectation` held.
    ///
    /// Panics if the verification fails.
    pub fn verify(self) { /* drop self */ }
}

/// If the `Expectation` is dropped it is automatically verified.
impl Drop for Expectation {
    fn drop(&mut self) {
        if let &mut Expectation::Failed { .. } = self {
            println!("{}", self);
            if !std::thread::panicking() {
                panic!("Some expectations failed.")
            }
        }
    }
}

impl Display for Expectation {
    fn fmt(&self, f: &mut Formatter) -> FormatResult {
        match self {
            &Expectation::Failed { ref assertion, ref file, ref line, ref error_msg } => {
                write!(f, "Expectation '{}' failed, originating from {}:{}\n\t{}",
                       assertion, file, line, error_msg
                )
            },
            _ => write!(f, "The expectation has been satisfied")
        }
    }
}

pub mod matchers;
<commit_msg>fix add imports needed by macros directly into the macros (removes unnecessary imports)<commit_after>/* Copyright 2017 Christopher Bacher
 *
 * 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
 *
 * http://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.
 */

//! Galvanic-assert: Matcher-based assertions for easier testing
//! ============================================================
//! This crate provides a new assertion macros (`assert_that!`, `expect_that!`, `get_expectation_for!`) based on **matching predicates** (matchers) to
//!
//!  * make **writing** asserts easier
//!  * make **reading** asserts comprehendable
//!  * easily **extend** the assertion framework
//!  * provide a large list **common matchers**
//!  * integrate with **galvanic-test** and **galvanic-mock** (both still in development ... stay tuned!)
//!  * be used with your favourite test framework
//!
//! The crate will be part of **galvanic**---a complete test framework for **Rust**.

use std::fmt::{Debug, Display, Formatter, Result as FormatResult};

/// States that the asserted values satisfies the required properties of the supplied `Matcher`.
///
/// The postulated assertion is verfied immediately and panics if it is not satisfied.
/// The macro comes in three different forms:
///
///  1. Assert that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     assert_that!(EXPRESSION);
///     assert_that!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Assert that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult`.
///
///     ```rust,ignore
///     assert_that!(&1, eq(1));
///     assert_that!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Assert that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     assert_that!(panic!("panic"), panics);
///     assert_that!(1+1, does not panic);
///     ```
#[macro_export]
macro_rules! assert_that {
    ( $actual: expr, panics ) => {{
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_ok() {
            panic!("\nFailed assertion; expected expression to panic")
        }
    }};
    ( $actual: expr, does not panic ) => {
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_err() {
            panic!("\nFailed assertion; expression panicked unexpectantly")
        }
    };
    ( $actual: expr) => {{
        if !$actual {
            panic!("\nFailed assertion; '{}' is not true", stringify!($actual));
        }
    }};
    ( $actual: expr , otherwise $reason: expr ) => {{
        if !$actual {
            panic!("\nFailed assertion; expression '{}' is not true,\n    Because: {}",
                   stringify!($actual), $reason
            );
        }
    }};
    ( $actual: expr, $matcher: expr ) => {{
        use galvanic_assert::MatchResult;
        //use std::borrow::Borrow;
        // store the actual value to borrow it
        let value = $actual;
        // use borrow to obtain a reference of type &T (either from a value of type T or of &T itself---the beauty of the Borrow)
        //let ref_to_value: &_ = value.borrow();
        // store matcher so it's dropped before the actual value (reverse order of declaration)
        let m = $matcher;
        match m.check(value) {
            MatchResult::Matched { .. } => { },
            MatchResult::Failed { name, reason } => {
                panic!("\nFailed assertion of matcher: {}\n{}", name, reason)
            }
        }
    }};
}

/// States that the asserted values satisfies the required properties of the supplied `Matcher`
/// and returns an `Expectation` object to inspect the results at a later time.
///
/// The postulated assertion is verfied immediately,
/// but the returned `Expectation` defers a potential panic either until `Expectation::verify` is called
/// or the `Expectation` object is dropped.
/// It is safe for multiple expectations to fail the assertion code will prevent nested panics.
///
/// The macro comes in three different forms:
///
///  1. Expect that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(EXPRESSION);
///     let e2 = get_expectation_for!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Expect that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult`.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(&1, eq(1));
///     let e2 = get_expectation_for!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Expect that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     let e1 = get_expectation_for!(panic!("panic"), panics);
///     let e2 = get_expectation_for!(&1+1, does not panic);
///     ```
///
/// An expectation can be verfied manually
///
/// ```rust,ignore
/// let e1 = get_expectation_for!(&1+1, equal_to(0));
/// let e2 = get_expectation_for!(&1+1, less_than(4)); // is executed
/// e1.verify();
/// let e3 = get_expectation_for!(&1+1, panics); // is never executed as e1 panics
/// ```
/// or is automatically verfied on drop.
///
/// ```rust,ignore
/// {
///     let e1 = get_expectation_for!(&1+1, equal_to(0));
///     let e2 = get_expectation_for!(&1+1, less_than(4)); // is executed
/// }
/// let e3 = get_expectation_for!(1+1, panics); // is never executed as e1 panics
/// ```
#[macro_export]
macro_rules! get_expectation_for {
    ( $actual: expr, panics ) => {{
        use galvanic_assert::Expectation;
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_ok() {
            let assertion = format!("'{}, panics'", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                "Expected expression to panic".to_string()
            )
        } else {
            Expectation::satisfied()
        }
    }};
    ( $actual: expr, does not panic ) => {{
        use galvanic_assert::Expectation;
        let result = std::panic::catch_unwind(|| { $actual; });
        if result.is_err() {
            let assertion = format!("'{}, does not panic'", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                "Expression panicked unexpectantly".to_string()
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr) => {{
        use galvanic_assert::Expectation;
        if !$actual {
            let assertion = format!("'{}' is true", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                format!("'{}' is not true", stringify!($actual))
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr , otherwise $reason: expr ) => {{
        use galvanic_assert::Expectation;
        if !$actual {
            let assertion = format!("'{}' is true", stringify!($actual));
            Expectation::failed(assertion, file!().to_string(), line!(),
                                format!("'{}' is not true,\n\tBecause: {}",
                                        stringify!($actual), $reason)
            )
        } else { Expectation::satisfied() }
    }};
    ( $actual: expr, $matcher: expr ) => {{
        use galvanic_assert::{Expectation, MatchResult};
        let value = $actual;
        let m = $matcher;
        match m.check(value) {
            MatchResult::Matched { .. } => { Expectation::satisfied() },
            MatchResult::Failed { name, reason } => {
                let assertion = format!("'{}' matches '{}'", stringify!($actual), stringify!($matcher));
                Expectation::failed(assertion, file!().to_string(), line!(),
                                    format!("Failed assertion of matcher: {}\n{}", name, reason)
                )
            }
        }
    }};
}

/// States that the asserted values satisfies the required properties of the supplied `Matcher`
/// but waits until the end of the block to inspect the results.
///
/// The postulated assertion is verfied immediately,
/// but a potential panic is deferred until the end of the block wherein the expectation is stated.
/// It is safe for multiple expectations to fail.
/// The assertion code will prevent nested panics.
///
/// The macro comes in three different forms:
///
///  1. Expect that some expression is true, supplied with an optional error message.
///
///     ```rust,ignore
///     expect_that!(EXPRESSION);
///     expect_that!(EXPRESSION, otherwise "some error message");
///     ```
///  2. Expect that some expression satifies the properties of some `Matcher`.
///     The `Matcher` is either predefined, a user defined type with a `Matcher` implementation, or a closure returning a `MatchResult
///
///     ```rust,ignore
///     expect_that!(&1, eq(1));
///     expect_that!(&1, |x| {
///         let builder = MatchResultBuilder::for_("my_matcher");
///         if x == 1 { builder.matched } else { builder.failed_because("some reason") }
///     })
///     ```
///  3. Expect that some expression is expected to panic/not panic.
///
///     ```rust,ignore
///     expect_that!(panic!("panic"), panics);
///     expect_that!(1+1, does not panic);
///     ```
///
/// An expectation is verified at the end of the block it is stated in:
///
/// ```rust,ignore
/// {
///     expect_that!(&1+1, equal_to(0));
///     expect_that!(&1+1, less_than(4)); // is executed
/// }
/// expect_that!(1+1, panics); // is never executed as e1 panics
/// ```
#[macro_export]
macro_rules! expect_that {
    ( $actual: expr, panics ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, panics); };
    ( $actual: expr, does not panic ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, does not panic); };
    ( $actual: expr) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual); };
    ( $actual: expr , otherwise $reason: expr ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, otherwise $reason); };
    ( $actual: expr, $matcher: expr ) => { #[allow(unused_variables)] let expectation = get_expectation_for!($actual, $matcher); };
}

/// The trait which has to be implemented by all matchers.
pub trait Matcher<'a, T:'a> {
    /// Checks the passed value if it satisfies the `Matcher`.
    ///
    /// Values are always taken as immutable reference as the actual value shouldn't be changed by the matcher.
    fn check(&self, actual: &'a T) -> MatchResult;
}

/// A closures can be used as a `Matcher`.
///
/// The closure must be repeatably callable in case that the matcher is combined with another matcher.
impl<'a, T:'a, F> Matcher<'a,T> for F
where F: Fn(&'a T) -> MatchResult + ?Sized {
    fn check(&self, actual: &'a T) -> MatchResult {
        self(actual)
    }
}

/// The return type of any `Machter`
pub enum MatchResult {
    /// Indicates that the `Matcher` matched the value under inspection.
    Matched {
        /// The `name` of the `Matcher`
        name: String
    },
    /// Indicates that the `Matcher` failed to match the value under inspection.
    Failed {
        /// The `name` of the `Matcher`
        name: String,
        /// The `reason` why the `Matcher` failed
        reason: String
    }
}

/// A builder for creating `MatchResult`s.
///
/// Create a new builder with `new()` or `for_()`
/// and finalize it either with `matched()`, `failed_because()`, or `failed_comparison()`.
pub struct MatchResultBuilder {
    matcher_name: String
}

impl MatchResultBuilder {
    /// Creates a `MatchResultBuilder` for an anonymous `Matcher`.
    pub fn new() -> MatchResultBuilder {
        MatchResultBuilder {
            matcher_name: "_unknown_".to_owned()
        }
    }

    /// Creates `MatchResultBuilder` for a `Matcher` with the given `name`
    pub fn for_(name: &str) -> MatchResultBuilder {
        MatchResultBuilder {
            matcher_name: name.to_owned()
        }
    }

    /// Finalzes the builder indicating that the `Matcher` matched the inspected value.
    pub fn matched(self) -> MatchResult {
        MatchResult::Matched { name: self.matcher_name }
    }

    /// Finalzes the builder indicating that the `Matcher` failed to the inspected value.
    ///
    /// The `reason` should give a short indication why the matcher failed.
    pub fn failed_because(self, reason: &str) -> MatchResult {
        MatchResult::Failed {
            name: self.matcher_name,
            reason: format!("  Because: {}", reason)
        }
    }

    /// Finalzes the builder indicating that the `Matcher` failed to the inspected value.
    ///
    /// The `actual` and `expected` value are used the generate a useful error message.
    pub fn failed_comparison<T: Debug>(self, actual: &T, expected: &T) -> MatchResult {
        MatchResult::Failed {
            name: self.matcher_name,
            reason: format!("  Expected: {:?}\n  Got: {:?}", expected, actual)
        }
    }
}

/// The result of a deferred assertion.
///
///
pub enum Expectation {
    Failed {
        /// A representation of the failed assertion.
        assertion: String,
        /// The file where the expection has been created.
        file: String,
        /// The source code line where the expectation has been created.
        line: u32,
        /// The reason why the expectation has not been met.
        error_msg: String
    },
    Satisfied
}

impl Expectation {
    /// Creates a failed `Expectation`
    pub fn failed(assertion:String, file: String, line: u32, error_msg: String) -> Expectation {
        Expectation::Failed {
            assertion: assertion,
            file: file,
            line: line,
            error_msg: error_msg
        }
    }

    /// Create a satisfied `Expectation`
    pub fn satisfied() -> Expectation {
        Expectation::Satisfied
    }

    /// Verifies if the asseration given by the `Expectation` held.
    ///
    /// Panics if the verification fails.
    pub fn verify(self) { /* drop self */ }
}

/// If the `Expectation` is dropped it is automatically verified.
impl Drop for Expectation {
    fn drop(&mut self) {
        if let &mut Expectation::Failed { .. } = self {
            println!("{}", self);
            if !std::thread::panicking() {
                panic!("Some expectations failed.")
            }
        }
    }
}

impl Display for Expectation {
    fn fmt(&self, f: &mut Formatter) -> FormatResult {
        match self {
            &Expectation::Failed { ref assertion, ref file, ref line, ref error_msg } => {
                write!(f, "Expectation '{}' failed, originating from {}:{}\n\t{}",
                       assertion, file, line, error_msg
                )
            },
            _ => write!(f, "The expectation has been satisfied")
        }
    }
}

pub mod matchers;
<|endoftext|>


<commit_before>//! Guessing of MIME types by file extension.
//!
//! Uses a static list of file-extension : MIME type mappings.
#![cfg_attr(feature = "bench", feature(test))]

extern crate mime;
extern crate phf;
extern crate unicase;

use mime::{Mime, TopLevel, SubLevel};
use unicase::UniCase;

use std::ffi::OsStr;
use std::path::Path;

include!("mime_types_generated.rs");

macro_rules! try_opt(
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    )
);

#[cfg(test)]
#[path = "mime_types.rs"]
mod mime_types_src;

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then the MIME type is assumed to be `application/octet-stream`.
///
/// ##Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn guess_mime_type<P: AsRef<Path>>(path: P) -> Mime {
    guess_mime_type_opt(path)
        .unwrap_or_else(octet_stream)
}

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
/// ##Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn guess_mime_type_opt<P: AsRef<Path>>(path: P) -> Option<Mime> {
    let ext = path.as_ref().extension().and_then(OsStr::to_str).unwrap_or("");

    get_mime_type_opt(ext)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `application/octet-stream` is returned.
pub fn get_mime_type(search_ext: &str) -> Mime {
    get_mime_type_opt(search_ext)
        .unwrap_or_else(octet_stream)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `None` is returned.
pub fn get_mime_type_opt(search_ext: &str) -> Option<Mime> {
    get_mime_type_str(search_ext)
        .map(|mime| mime.parse::<Mime>().unwrap())
}

/// Get the MIME type string associated with a file extension. Case-insensitive.
///
/// If `search_ext` is not already lowercase,
/// it will be converted to lowercase to facilitate the search.
///
/// Returns `None` if `search_ext` is empty or an associated extension was not found.
pub fn get_mime_type_str(search_ext: &str) -> Option<&'static str> {
    if search_ext.is_empty() { return None; }

    map_lookup_unicase(&MIME_TYPES, search_ext).cloned()
}

/// Get a list of known extensions for a given `Mime` type. Ignores parameters
/// (only searches with `<main type>/<subtype>`). Case-insensitive (for extension types).

///
/// Returns `None` if the mime is unknown.
pub fn get_extensions(mime: &Mime) -> Option<&'static [&'static str]> {
    let no_param_mime = format!("{}/{}", mime.0, mime.1);
    get_extensions_str(&no_param_mime);
}

/// Get a list of known extensions for a mime type. Ignores parameters (only searches
/// `<main type>/<subtype>`). Case-insensitive.

///
/// Returns `None` if the mime is unknown.
pub fn get_extensions_str(mut mime_str: &str) -> Option<&'static [&'static str]> {
    if let Some(sep_idx) = mime_str.find(';') {
        mime_str = &mime_str[..sep_idx];
    }

    // Need to map &&'static [..] to &'static [..] inside the Option
    map_lookup_unicase(&REV_MAPPINGS, mime_str).map(|&exts| exts)
}

/// Get the MIME type for `application/octet-stream` (generic binary stream)
pub fn octet_stream() -> Mime {
    // FIXME: use new representation when https://github.com/hyperium/mime.rs/pull/42
    // is merged.
    Mime(TopLevel::Application, SubLevel::Ext("octet-stream".into()), Vec::new())
}

fn map_lookup_unicase<'map, V>(map: &'map phf::Map<UniCase<&'static str>, V>, key: &str) -> Option<&'map V> {
    // This transmute should be safe as `get` will not store the reference with
    // the expanded lifetime. This is due to `Borrow` being overly strict and
    // can't have an impl for `&'static str` to `Borrow<&'a str>`.
    //
    // See https://github.com/rust-lang/rust/issues/28853#issuecomment-158735548
    let key = unsafe { ::std::mem::transmute::<_, &'static str>(key) };
    map.get(&UniCase(key))
}

#[cfg(test)]
mod tests {
    use mime::Mime;
    use std::ascii::AsciiExt;
    use std::path::Path;
    use super::{get_mime_type, guess_mime_type, MIME_TYPES};
    use super::{get_mime_type_opt, guess_mime_type_opt};

    #[test]
    fn test_mime_type_guessing() {
        assert_eq!(get_mime_type("gif").to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type("TXT").to_string(), "text/plain".to_string());
        assert_eq!(get_mime_type("blahblah").to_string(), "application/octet-stream".to_string());

        assert_eq!(guess_mime_type(Path::new("/path/to/file.gif")).to_string(), "image/gif".to_string());
        assert_eq!(guess_mime_type("/path/to/file.gif").to_string(), "image/gif".to_string());
    }

    #[test]
    fn test_mime_type_guessing_opt() {
        assert_eq!(get_mime_type_opt("gif").unwrap().to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type_opt("TXT").unwrap().to_string(), "text/plain".to_string());
        assert_eq!(get_mime_type_opt("blahblah"), None);

        assert_eq!(guess_mime_type_opt("/path/to/file.gif").unwrap().to_string(), "image/gif".to_string());
        assert_eq!(guess_mime_type_opt("/path/to/file"), None);
    }

    #[test]
    fn test_are_mime_types_parseable() {
        for (_, mime) in &MIME_TYPES {
            mime.parse::<Mime>().unwrap();
        }
    }

    // RFC: Is this test necessary anymore? --@cybergeek94, 2/1/2016
    #[test]
    fn test_are_extensions_ascii() {
        for (ext, _) in &MIME_TYPES {
            assert!(ext.is_ascii(), "Extension not ASCII: {:?}", ext);
        }
    }

    #[test]
    fn test_are_extensions_sorted() {
        use mime_types_src::MIME_TYPES;

        for (&(ext, _), &(n_ext, _)) in MIME_TYPES.iter().zip(MIME_TYPES.iter().skip(1)) {
            assert!(
                ext <= n_ext,
                "Extensions in src/mime_types should be sorted alphabetically
                in ascending order. Failed assert: {:?} <= {:?}",
                ext, n_ext
            );
        }
    }

}

#[cfg(feature = "bench")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::{get_mime_type_str, MIME_TYPES};

    /// WARNING: this may take a while!
    #[bench]
    fn bench_mime_str(b: &mut Bencher) {
        for (mime_ext, _) in &MIME_TYPES {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }

    #[bench]
    fn bench_mime_str_uppercase(b: &mut Bencher) {
        let uppercased : Vec<_> = MIME_TYPES.into_iter().map(|(s, _)| s.to_uppercase()).collect();

        for mime_ext in &uppercased {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }
}
<commit_msg>Fix typo<commit_after>//! Guessing of MIME types by file extension.
//!
//! Uses a static list of file-extension : MIME type mappings.
#![cfg_attr(feature = "bench", feature(test))]

extern crate mime;
extern crate phf;
extern crate unicase;

use mime::{Mime, TopLevel, SubLevel};
use unicase::UniCase;

use std::ffi::OsStr;
use std::path::Path;

include!("mime_types_generated.rs");

macro_rules! try_opt(
    ($expr:expr) => (
        match $expr {
            Some(val) => val,
            None => return None,
        }
    )
);

#[cfg(test)]
#[path = "mime_types.rs"]
mod mime_types_src;

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then the MIME type is assumed to be `application/octet-stream`.
///
/// ##Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn guess_mime_type<P: AsRef<Path>>(path: P) -> Mime {
    guess_mime_type_opt(path)
        .unwrap_or_else(octet_stream)
}

/// Guess the MIME type of `path` by its extension (as defined by `Path::extension()`).
///
/// If `path` has no extension, or its extension has no known MIME type mapping,
/// then `None` is returned.
///
/// ##Note
/// **Guess** is the operative word here, as there are no guarantees that the contents of the file
/// that `path` points to match the MIME type associated with the path's extension.
///
/// Take care when processing files with assumptions based on the return value of this function.
pub fn guess_mime_type_opt<P: AsRef<Path>>(path: P) -> Option<Mime> {
    let ext = path.as_ref().extension().and_then(OsStr::to_str).unwrap_or("");

    get_mime_type_opt(ext)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `application/octet-stream` is returned.
pub fn get_mime_type(search_ext: &str) -> Mime {
    get_mime_type_opt(search_ext)
        .unwrap_or_else(octet_stream)
}

/// Get the MIME type associated with a file extension.
///
/// If there is no association for the extension, or `ext` is empty,
/// `None` is returned.
pub fn get_mime_type_opt(search_ext: &str) -> Option<Mime> {
    get_mime_type_str(search_ext)
        .map(|mime| mime.parse::<Mime>().unwrap())
}

/// Get the MIME type string associated with a file extension. Case-insensitive.
///
/// If `search_ext` is not already lowercase,
/// it will be converted to lowercase to facilitate the search.
///
/// Returns `None` if `search_ext` is empty or an associated extension was not found.
pub fn get_mime_type_str(search_ext: &str) -> Option<&'static str> {
    if search_ext.is_empty() { return None; }

    map_lookup_unicase(&MIME_TYPES, search_ext).cloned()
}

/// Get a list of known extensions for a given `Mime` type. Ignores parameters
/// (only searches with `<main type>/<subtype>`). Case-insensitive (for extension types).

///
/// Returns `None` if the mime is unknown.
pub fn get_extensions(mime: &Mime) -> Option<&'static [&'static str]> {
    let no_param_mime = format!("{}/{}", mime.0, mime.1);
    get_extensions_str(&no_param_mime)
}

/// Get a list of known extensions for a mime type. Ignores parameters (only searches
/// `<main type>/<subtype>`). Case-insensitive.

///
/// Returns `None` if the mime is unknown.
pub fn get_extensions_str(mut mime_str: &str) -> Option<&'static [&'static str]> {
    if let Some(sep_idx) = mime_str.find(';') {
        mime_str = &mime_str[..sep_idx];
    }

    // Need to map &&'static [..] to &'static [..] inside the Option
    map_lookup_unicase(&REV_MAPPINGS, mime_str).map(|&exts| exts)
}

/// Get the MIME type for `application/octet-stream` (generic binary stream)
pub fn octet_stream() -> Mime {
    // FIXME: use new representation when https://github.com/hyperium/mime.rs/pull/42
    // is merged.
    Mime(TopLevel::Application, SubLevel::Ext("octet-stream".into()), Vec::new())
}

fn map_lookup_unicase<'map, V>(map: &'map phf::Map<UniCase<&'static str>, V>, key: &str) -> Option<&'map V> {
    // This transmute should be safe as `get` will not store the reference with
    // the expanded lifetime. This is due to `Borrow` being overly strict and
    // can't have an impl for `&'static str` to `Borrow<&'a str>`.
    //
    // See https://github.com/rust-lang/rust/issues/28853#issuecomment-158735548
    let key = unsafe { ::std::mem::transmute::<_, &'static str>(key) };
    map.get(&UniCase(key))
}

#[cfg(test)]
mod tests {
    use mime::Mime;
    use std::ascii::AsciiExt;
    use std::path::Path;
    use super::{get_mime_type, guess_mime_type, MIME_TYPES};
    use super::{get_mime_type_opt, guess_mime_type_opt};

    #[test]
    fn test_mime_type_guessing() {
        assert_eq!(get_mime_type("gif").to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type("TXT").to_string(), "text/plain".to_string());
        assert_eq!(get_mime_type("blahblah").to_string(), "application/octet-stream".to_string());

        assert_eq!(guess_mime_type(Path::new("/path/to/file.gif")).to_string(), "image/gif".to_string());
        assert_eq!(guess_mime_type("/path/to/file.gif").to_string(), "image/gif".to_string());
    }

    #[test]
    fn test_mime_type_guessing_opt() {
        assert_eq!(get_mime_type_opt("gif").unwrap().to_string(), "image/gif".to_string());
        assert_eq!(get_mime_type_opt("TXT").unwrap().to_string(), "text/plain".to_string());
        assert_eq!(get_mime_type_opt("blahblah"), None);

        assert_eq!(guess_mime_type_opt("/path/to/file.gif").unwrap().to_string(), "image/gif".to_string());
        assert_eq!(guess_mime_type_opt("/path/to/file"), None);
    }

    #[test]
    fn test_are_mime_types_parseable() {
        for (_, mime) in &MIME_TYPES {
            mime.parse::<Mime>().unwrap();
        }
    }

    // RFC: Is this test necessary anymore? --@cybergeek94, 2/1/2016
    #[test]
    fn test_are_extensions_ascii() {
        for (ext, _) in &MIME_TYPES {
            assert!(ext.is_ascii(), "Extension not ASCII: {:?}", ext);
        }
    }

    #[test]
    fn test_are_extensions_sorted() {
        use mime_types_src::MIME_TYPES;

        for (&(ext, _), &(n_ext, _)) in MIME_TYPES.iter().zip(MIME_TYPES.iter().skip(1)) {
            assert!(
                ext <= n_ext,
                "Extensions in src/mime_types should be sorted alphabetically
                in ascending order. Failed assert: {:?} <= {:?}",
                ext, n_ext
            );
        }
    }

}

#[cfg(feature = "bench")]
mod bench {
    extern crate test;

    use self::test::Bencher;

    use super::{get_mime_type_str, MIME_TYPES};

    /// WARNING: this may take a while!
    #[bench]
    fn bench_mime_str(b: &mut Bencher) {
        for (mime_ext, _) in &MIME_TYPES {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }

    #[bench]
    fn bench_mime_str_uppercase(b: &mut Bencher) {
        let uppercased : Vec<_> = MIME_TYPES.into_iter().map(|(s, _)| s.to_uppercase()).collect();

        for mime_ext in &uppercased {
            b.iter(|| {
                get_mime_type_str(mime_ext).expect(mime_ext);
            });
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// 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
//
//   http://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.

//! Demo [Exonum][exonum] service implementing a simple cryptocurrency.
//! See [the documentation][docs] for a detailed step-by-step guide how to approach this demo,
//! and [the reporitory README][readme] on how to use, test, and contribute to it.
//!
//! **Note.** The service in this crate is intended for demo purposes only. It is not intended
//! for use in production.
//!
//! [exonum]: https://github.com/exonum/exonum
//! [docs]: https://exonum.com/doc/get-started/create-service
//! [readme]: https://github.com/exonum/cryptocurrency#readme

#![deny(missing_docs)]

// Import crates with necessary types into a new project.

extern crate serde;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

// Import necessary types from crates.

use exonum::blockchain::{Blockchain, Service, Transaction, ApiContext};
use exonum::encoding::serialize::FromHex;
use exonum::node::{TransactionSend, ApiSender};
use exonum::messages::{RawTransaction, Message};
use exonum::storage::{Fork, MapIndex, Snapshot};
use exonum::crypto::PublicKey;
use exonum::encoding;
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;
use serde::Deserialize;

// // // // // // // // // // CONSTANTS // // // // // // // // // //

/// Service ID for the `Service` trait.
const SERVICE_ID: u16 = 1;

// Constants for transaction types within the service.
const TX_CREATE_WALLET_ID: u16 = 1;
const TX_TRANSFER_ID: u16 = 2;

/// Initial balance of a newly created wallet.
const INIT_BALANCE: u64 = 100;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

// Declare the data to be stored in the blockchain, namely wallets with balances.
// See [serialization docs][1] for details.
//
// [1]: https://exonum.com/doc/architecture/serialization

encoding_struct! {
    /// Wallet struct used to persist data within the service.
    struct Wallet {
        const SIZE = 48;

        /// Public key of the wallet owner.
        field pub_key:            &PublicKey  [00 => 32]
        /// Name of the wallet owner.
        field name:               &str        [32 => 40]
        /// Current balance.
        field balance:            u64         [40 => 48]
    }
}

/// Additional methods for managing balance of the wallet in an immutable fashion.
impl Wallet {
    /// Returns a copy of this wallet with the balance increased by the specified amount.
    pub fn increase(self, amount: u64) -> Self {
        let balance = self.balance() + amount;
        Self::new(self.pub_key(), self.name(), balance)
    }

    /// Returns a copy of this wallet with the balance decreased by the specified amount.
    pub fn decrease(self, amount: u64) -> Self {
        debug_assert!(self.balance() >= amount);
        let balance = self.balance() - amount;
        Self::new(self.pub_key(), self.name(), balance)
    }
}

// // // // // // // // // // DATA LAYOUT // // // // // // // // // //

/// Schema of the key-value storage used by the demo cryptocurrency service.
pub struct CurrencySchema<T> {
    view: T,
}

/// Declare the layout of data managed by the service. An instance of [`MapIndex`] is used
/// to keep wallets in the storage. Index values are serialized [`Wallet`] structs.
///
/// [`MapIndex`]: https://exonum.com/doc/architecture/storage#mapindex
/// [`Wallet`]: struct.Wallet.html
impl<T: AsRef<Snapshot>> CurrencySchema<T> {
    /// Creates a new schema instance.
    pub fn new(view: T) -> Self {
        CurrencySchema { view }
    }

    /// Returns an immutable version of the wallets table.
    pub fn wallets(&self) -> MapIndex<&Snapshot, PublicKey, Wallet> {
        MapIndex::new("cryptocurrency.wallets", self.view.as_ref())
    }

    /// Gets a specific wallet from the storage.
    pub fn wallet(&self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

/// A mutable version of the schema with an additional method to persist wallets
/// to the storage.
impl<'a> CurrencySchema<&'a mut Fork> {
    /// Returns a mutable version of the wallets table.
    pub fn wallets_mut(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        MapIndex::new("cryptocurrency.wallets", &mut self.view)
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

message! {
    /// Transaction type for creating a new wallet.
    ///
    /// See [the `Transaction` trait implementation](#impl-Transaction) for details how
    /// `TxCreateWallet` transactions are processed.
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_CREATE_WALLET_ID;
        const SIZE = 40;

        /// Public key of the wallet's owner.
        field pub_key:     &PublicKey  [00 => 32]
        /// UTF-8 string with the owner's name.
        field name:        &str        [32 => 40]
    }
}

message! {
    /// Transaction type for transferring tokens between two wallets.
    ///
    /// See [the `Transaction` trait implementation](#impl-Transaction) for details how
    /// `TxTransfer` transactions are processed.
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        /// Public key of the sender.
        field from:        &PublicKey  [00 => 32]
        /// Public key of the receiver.
        field to:          &PublicKey  [32 => 64]
        /// Number of tokens to transfer from sender's account to receiver's account.
        field amount:      u64         [64 => 72]
        /// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
        ///
        /// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    /// Verifies integrity of the transaction by checking the transaction
    /// signature.
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    /// If a wallet with the specified public key is not registered, then creates a new wallet
    /// with the specified public key and name, and an initial balance of 100.
    /// Otherwise, performs no op.
    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema::new(view);
        if schema.wallet(self.pub_key()).is_none() {
            let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets_mut().put(self.pub_key(), wallet);
        }
    }

    /// Provides information about the transaction to be used in the blockchain explorer.
    fn info(&self) -> serde_json::Value {
        serde_json::to_value(&self).expect("Cannot serialize transaction to JSON")
    }
}

impl Transaction for TxTransfer {
    /// Checks if the sender is not the receiver, and checks correctness of the
    /// sender's signature.
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    /// Retrieves two wallets to apply the transfer; they should be previously registered
    /// with the help of [`TxCreateWallet`] transactions. Checks the sender's
    /// balance and applies changes to the balances of the wallets if the sender's balance
    /// is sufficient. Otherwise, performs no op.
    ///
    /// [`TxCreateWallet`]: struct.TxCreateWallet.html
    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema::new(view);
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(sender), Some(receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                let sender = sender.decrease(amount);
                let receiver = receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets_mut();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }

    /// Provides information about the transaction to be used in the blockchain explorer.
    fn info(&self) -> serde_json::Value {
        serde_json::to_value(&self).expect("Cannot serialize transaction to JSON")
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

/// Container for the service API.
#[derive(Clone)]
struct CryptocurrencyApi {
    channel: ApiSender,
    blockchain: Blockchain,
}

impl CryptocurrencyApi {
    /// Endpoint for getting a single wallet.
    fn get_wallet(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let wallet_key = path.last().unwrap();
        let public_key = PublicKey::from_hex(wallet_key).map_err(ApiError::FromHex)?;

        let wallet = {
            let snapshot = self.blockchain.snapshot();
            let schema = CurrencySchema::new(snapshot);
            schema.wallet(&public_key)
        };

        if let Some(wallet) = wallet {
            self.ok_response(&serde_json::to_value(wallet).unwrap())
        } else {
            self.not_found_response(&serde_json::to_value("Wallet not found").unwrap())
        }
    }

    /// Endpoint for dumping all wallets from the storage.
    fn get_wallets(&self, _: &mut Request) -> IronResult<Response> {
        let snapshot = self.blockchain.snapshot();
        let schema = CurrencySchema::new(snapshot);
        let idx = schema.wallets();
        let wallets: Vec<Wallet> = idx.values().collect();

        self.ok_response(&serde_json::to_value(&wallets).unwrap())
    }

    /// Common processing for transaction-accepting endpoints.
    fn post_transaction<T>(&self, req: &mut Request) -> IronResult<Response>
    where
        T: Transaction + Clone + for<'de> Deserialize<'de>,
    {
        match req.get::<bodyparser::Struct<T>>() {
            Ok(Some(transaction)) => {
                let transaction: Box<Transaction> = Box::new(transaction);
                let tx_hash = transaction.hash();
                self.channel.send(transaction).map_err(ApiError::from)?;
                self.ok_response(&json!({
                    "tx_hash": tx_hash
                }))
            }
            Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
            Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
        }
    }
}

/// `Api` trait implementation.
///
/// `Api` facilitates conversion between transactions/read requests and REST
/// endpoints; for example, it parses `POST`ed JSON into the binary transaction
/// representation used in Exonum internally.
impl Api for CryptocurrencyApi {
    fn wire(&self, router: &mut Router) {
        let self_ = self.clone();
        let post_create_wallet =
            move |req: &mut Request| self_.post_transaction::<TxCreateWallet>(req);
        let self_ = self.clone();
        let post_transfer = move |req: &mut Request| self_.post_transaction::<TxTransfer>(req);
        let self_ = self.clone();
        let get_wallets = move |req: &mut Request| self_.get_wallets(req);
        let self_ = self.clone();
        let get_wallet = move |req: &mut Request| self_.get_wallet(req);

        // Bind handlers to specific routes.
        router.post("/v1/wallets", post_create_wallet, "post_create_wallet");
        router.post("/v1/wallets/transfer", post_transfer, "post_transfer");
        router.get("/v1/wallets", get_wallets, "get_wallets");
        router.get("/v1/wallet/:pub_key", get_wallet, "get_wallet");
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

/// Demo cryptocurrency service.
///
/// See [the crate documentation](index.html) for context.
///
/// # Public REST API
///
/// In all APIs, the request body (if applicable) and response are JSON-encoded.
///
/// ## Retrieve single wallet
///
/// GET `v1/wallet/:pub_key`
///
/// Returns information about a wallet with the specified public key (hex-encoded).
/// If a wallet with the specified pubkey is not in the storage, returns a string
/// `"Wallet not found"` with the HTTP 404 status.
///
/// ## Dump wallets
///
/// GET `v1/wallets`
///
/// Returns an array of all wallets in the storage.
///
/// ## Create new wallet
///
/// POST `v1/wallets`
///
/// Accepts a [`TxCreateWallet`] transaction from an external client. Returns the hex-encoded
/// hash of the transaction encumbered in an object: `{ "tx_hash": <hash> }`.
///
/// ## Transfer between wallets
///
/// POST `v1/wallets/transfer`
///
/// Accepts a [`TxTransfer`] transaction from an external client. Returns the hex-encoded
/// hash of the transaction encumbered in an object: `{ "tx_hash": <hash> }`.
///
/// [`TxCreateWallet`]: struct.TxCreateWallet.html
/// [`TxTransfer`]: struct.TxTransfer.html
pub struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str {
        "cryptocurrency"
    }

    fn service_id(&self) -> u16 {
        SERVICE_ID
    }

    // Implement a method to deserialize transactions coming to the node.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType {
                    message_type: raw.message_type(),
                });
            }
        };
        Ok(trans)
    }

    // Create a REST `Handler` to process web requests to the node.
    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
            blockchain: ctx.blockchain().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}
<commit_msg>Update code to be compatible with v0.5<commit_after>// Copyright 2017 The Exonum Team
//
// 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
//
//   http://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.

//! Demo [Exonum][exonum] service implementing a simple cryptocurrency.
//! See [the documentation][docs] for a detailed step-by-step guide how to approach this demo,
//! and [the reporitory README][readme] on how to use, test, and contribute to it.
//!
//! **Note.** The service in this crate is intended for demo purposes only. It is not intended
//! for use in production.
//!
//! [exonum]: https://github.com/exonum/exonum
//! [docs]: https://exonum.com/doc/get-started/create-service
//! [readme]: https://github.com/exonum/cryptocurrency#readme

#![deny(missing_docs)]

// Import crates with necessary types into a new project.

extern crate serde;
#[macro_use]
extern crate serde_json;
#[macro_use]
extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

// Import necessary types from crates.

use exonum::blockchain::{Blockchain, Service, Transaction, ApiContext};
use exonum::encoding::serialize::FromHex;
use exonum::node::{TransactionSend, ApiSender};
use exonum::messages::{RawTransaction, Message};
use exonum::storage::{Fork, MapIndex, Snapshot};
use exonum::crypto::{Hash, PublicKey};
use exonum::encoding;
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;
use serde::Deserialize;

// // // // // // // // // // CONSTANTS // // // // // // // // // //

/// Service ID for the `Service` trait.
const SERVICE_ID: u16 = 1;

// Constants for transaction types within the service.
const TX_CREATE_WALLET_ID: u16 = 1;
const TX_TRANSFER_ID: u16 = 2;

/// Initial balance of a newly created wallet.
const INIT_BALANCE: u64 = 100;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

// Declare the data to be stored in the blockchain, namely wallets with balances.
// See [serialization docs][1] for details.
//
// [1]: https://exonum.com/doc/architecture/serialization

encoding_struct! {
    /// Wallet struct used to persist data within the service.
    struct Wallet {
        /// Public key of the wallet owner.
        pub_key: &PublicKey,
        /// Name of the wallet owner.
        name: &str,
        /// Current balance.
        balance: u64,
    }
}

/// Additional methods for managing balance of the wallet in an immutable fashion.
impl Wallet {
    /// Returns a copy of this wallet with the balance increased by the specified amount.
    pub fn increase(self, amount: u64) -> Self {
        let balance = self.balance() + amount;
        Self::new(self.pub_key(), self.name(), balance)
    }

    /// Returns a copy of this wallet with the balance decreased by the specified amount.
    pub fn decrease(self, amount: u64) -> Self {
        debug_assert!(self.balance() >= amount);
        let balance = self.balance() - amount;
        Self::new(self.pub_key(), self.name(), balance)
    }
}

// // // // // // // // // // DATA LAYOUT // // // // // // // // // //

/// Schema of the key-value storage used by the demo cryptocurrency service.
pub struct CurrencySchema<T> {
    view: T,
}

/// Declare the layout of data managed by the service. An instance of [`MapIndex`] is used
/// to keep wallets in the storage. Index values are serialized [`Wallet`] structs.
///
/// [`MapIndex`]: https://exonum.com/doc/architecture/storage#mapindex
/// [`Wallet`]: struct.Wallet.html
impl<T: AsRef<Snapshot>> CurrencySchema<T> {
    /// Creates a new schema instance.
    pub fn new(view: T) -> Self {
        CurrencySchema { view }
    }

    /// Returns an immutable version of the wallets table.
    pub fn wallets(&self) -> MapIndex<&Snapshot, PublicKey, Wallet> {
        MapIndex::new("cryptocurrency.wallets", self.view.as_ref())
    }

    /// Gets a specific wallet from the storage.
    pub fn wallet(&self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

/// A mutable version of the schema with an additional method to persist wallets
/// to the storage.
impl<'a> CurrencySchema<&'a mut Fork> {
    /// Returns a mutable version of the wallets table.
    pub fn wallets_mut(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        MapIndex::new("cryptocurrency.wallets", &mut self.view)
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

message! {
    /// Transaction type for creating a new wallet.
    ///
    /// See [the `Transaction` trait implementation](#impl-Transaction) for details how
    /// `TxCreateWallet` transactions are processed.
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_CREATE_WALLET_ID;

        /// Public key of the wallet's owner.
        pub_key: &PublicKey,
        /// UTF-8 string with the owner's name.
        name: &str,
    }
}

message! {
    /// Transaction type for transferring tokens between two wallets.
    ///
    /// See [the `Transaction` trait implementation](#impl-Transaction) for details how
    /// `TxTransfer` transactions are processed.
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;

        /// Public key of the sender.
        from: &PublicKey,
        /// Public key of the receiver.
        to: &PublicKey,
        /// Number of tokens to transfer from sender's account to receiver's account.
        amount: u64,
        /// Auxiliary number to guarantee [non-idempotence][idempotence] of transactions.
        ///
        /// [idempotence]: https://en.wikipedia.org/wiki/Idempotence
        seed: u64,
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    /// Verifies integrity of the transaction by checking the transaction
    /// signature.
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    /// If a wallet with the specified public key is not registered, then creates a new wallet
    /// with the specified public key and name, and an initial balance of 100.
    /// Otherwise, performs no op.
    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema::new(view);
        if schema.wallet(self.pub_key()).is_none() {
            let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets_mut().put(self.pub_key(), wallet);
        }
    }
}

impl Transaction for TxTransfer {
    /// Checks if the sender is not the receiver, and checks correctness of the
    /// sender's signature.
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    /// Retrieves two wallets to apply the transfer; they should be previously registered
    /// with the help of [`TxCreateWallet`] transactions. Checks the sender's
    /// balance and applies changes to the balances of the wallets if the sender's balance
    /// is sufficient. Otherwise, performs no op.
    ///
    /// [`TxCreateWallet`]: struct.TxCreateWallet.html
    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema::new(view);
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(sender), Some(receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                let sender = sender.decrease(amount);
                let receiver = receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets_mut();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

/// Container for the service API.
#[derive(Clone)]
struct CryptocurrencyApi {
    channel: ApiSender,
    blockchain: Blockchain,
}

impl CryptocurrencyApi {
    /// Endpoint for getting a single wallet.
    fn get_wallet(&self, req: &mut Request) -> IronResult<Response> {
        let path = req.url.path();
        let wallet_key = path.last().unwrap();
        let public_key = PublicKey::from_hex(wallet_key).map_err(ApiError::FromHex)?;

        let wallet = {
            let snapshot = self.blockchain.snapshot();
            let schema = CurrencySchema::new(snapshot);
            schema.wallet(&public_key)
        };

        if let Some(wallet) = wallet {
            self.ok_response(&serde_json::to_value(wallet).unwrap())
        } else {
            self.not_found_response(&serde_json::to_value("Wallet not found").unwrap())
        }
    }

    /// Endpoint for dumping all wallets from the storage.
    fn get_wallets(&self, _: &mut Request) -> IronResult<Response> {
        let snapshot = self.blockchain.snapshot();
        let schema = CurrencySchema::new(snapshot);
        let idx = schema.wallets();
        let wallets: Vec<Wallet> = idx.values().collect();

        self.ok_response(&serde_json::to_value(&wallets).unwrap())
    }

    /// Common processing for transaction-accepting endpoints.
    fn post_transaction<T>(&self, req: &mut Request) -> IronResult<Response>
    where
        T: Transaction + Clone + for<'de> Deserialize<'de>,
    {
        match req.get::<bodyparser::Struct<T>>() {
            Ok(Some(transaction)) => {
                let transaction: Box<Transaction> = Box::new(transaction);
                let tx_hash = transaction.hash();
                self.channel.send(transaction).map_err(ApiError::from)?;
                self.ok_response(&json!({
                    "tx_hash": tx_hash
                }))
            }
            Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
            Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
        }
    }
}

/// `Api` trait implementation.
///
/// `Api` facilitates conversion between transactions/read requests and REST
/// endpoints; for example, it parses `POST`ed JSON into the binary transaction
/// representation used in Exonum internally.
impl Api for CryptocurrencyApi {
    fn wire(&self, router: &mut Router) {
        let self_ = self.clone();
        let post_create_wallet =
            move |req: &mut Request| self_.post_transaction::<TxCreateWallet>(req);
        let self_ = self.clone();
        let post_transfer = move |req: &mut Request| self_.post_transaction::<TxTransfer>(req);
        let self_ = self.clone();
        let get_wallets = move |req: &mut Request| self_.get_wallets(req);
        let self_ = self.clone();
        let get_wallet = move |req: &mut Request| self_.get_wallet(req);

        // Bind handlers to specific routes.
        router.post("/v1/wallets", post_create_wallet, "post_create_wallet");
        router.post("/v1/wallets/transfer", post_transfer, "post_transfer");
        router.get("/v1/wallets", get_wallets, "get_wallets");
        router.get("/v1/wallet/:pub_key", get_wallet, "get_wallet");
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

/// Demo cryptocurrency service.
///
/// See [the crate documentation](index.html) for context.
///
/// # Public REST API
///
/// In all APIs, the request body (if applicable) and response are JSON-encoded.
///
/// ## Retrieve single wallet
///
/// GET `v1/wallet/:pub_key`
///
/// Returns information about a wallet with the specified public key (hex-encoded).
/// If a wallet with the specified pubkey is not in the storage, returns a string
/// `"Wallet not found"` with the HTTP 404 status.
///
/// ## Dump wallets
///
/// GET `v1/wallets`
///
/// Returns an array of all wallets in the storage.
///
/// ## Create new wallet
///
/// POST `v1/wallets`
///
/// Accepts a [`TxCreateWallet`] transaction from an external client. Returns the hex-encoded
/// hash of the transaction encumbered in an object: `{ "tx_hash": <hash> }`.
///
/// ## Transfer between wallets
///
/// POST `v1/wallets/transfer`
///
/// Accepts a [`TxTransfer`] transaction from an external client. Returns the hex-encoded
/// hash of the transaction encumbered in an object: `{ "tx_hash": <hash> }`.
///
/// [`TxCreateWallet`]: struct.TxCreateWallet.html
/// [`TxTransfer`]: struct.TxTransfer.html
pub struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str {
        "cryptocurrency"
    }

    fn service_id(&self) -> u16 {
        SERVICE_ID
    }

    // Implement a method to deserialize transactions coming to the node.
    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType {
                    message_type: raw.message_type(),
                });
            }
        };
        Ok(trans)
    }

    // Hashes for the service tables that will be included into the state hash.
    // To simplify things, we don't have [Merkelized tables][merkle] in the service storage
    // for now, so we return an empty vector.
    //
    // [merkle]: https://exonum.com/doc/architecture/storage/#merklized-indices
    fn state_hash(&self, _: &Snapshot) -> Vec<Hash> {
        vec![]
    }

    // Create a REST `Handler` to process web requests to the node.
    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
            blockchain: ctx.blockchain().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}
<|endoftext|>


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

use std::convert::From;
use std::cmp;
use std::fmt;
use std::mem;
use std::hash::{Hash, Hasher};
use std::ops::Deref;

/// Miscelaneous things used to integrate other code with Supercow, but which
/// is not of interest to end users.
pub mod aux {
    use std::rc::Rc;
    use std::sync::Arc;

    /// Marker trait indicating a `Deref`-like which always returns the same
    /// reference.
    ///
    /// This is not indended for general use outside Supercow. Notably, `Box`
    /// and mundane references satisfy this trait's requirements, but
    /// deliberately do not implement it. It is also not a subtrait of `Deref`
    /// due to some additional special logic around boxes.
    ///
    /// ## Unsafety
    ///
    /// Behaviour is undefined if the implementation does not always return the
    /// same reference from `deref()` for any particular implementing value
    /// (including if that value is moved).
    pub unsafe trait ConstDeref {
        type Target : ?Sized;
        fn const_deref(&self) -> &Self::Target;
    }

    unsafe impl<T : ?Sized> ConstDeref for Rc<T> {
        type Target = T;
        fn const_deref(&self) -> &T { self }
    }

    unsafe impl<T : ?Sized> ConstDeref for Arc<T> {
        type Target = T;
        fn const_deref(&self) -> &T { self }
    }

    unsafe impl<T : ConstDeref + ?Sized> ConstDeref for Box<T> {
        type Target = T::Target;
        fn const_deref(&self) -> &T::Target {
            (**self).const_deref()
        }
    }
}

use self::aux::*;

/// Defines a "feature set" for a custom `Supercow` type.
///
/// ## Syntax
///
/// ```
/// supercow_features!(
///   /// Some documentation, etc, if desired.
///   pub trait FeatureName: SomeTrait, SomeTrait);
/// supercow_features!(
///   pub trait FeatureName: Clone, SomeTrait, SomeTrait);
/// ```
///
/// ## Semantics
///
/// A public trait named `FeatureName` is defined which extends all the listed
/// traits, other than `Clone`, and in addition to `ConstDeref`. If listed,
/// `Clone` *must* come first. If `Clone` is listed, the trait gains a
/// `clone_boxed()` method and `Box<FeatureName>` is `Clone`. All types which
/// implement all the listed traits (including `Clone`) and `ConstDeref`
/// implement `FeatureName`.
#[macro_export]
macro_rules! supercow_features {
    // It's unclear why $req:path doesn't work, but apparently constraints
    // allow neither `path` nor `ty`.
    ($(#[$meta:meta])* pub trait $feature_name:ident: Clone $(, $req:ident)*) => {
        $(#[$meta])*
        pub trait $feature_name<'a>: $($req +)* $crate::aux::ConstDeref + 'a {
            fn clone_boxed
                (&self)
                 -> Box<$feature_name<'a, Target = Self::Target> + 'a>;
        }
        impl<'a, T : 'a + $($req +)* Clone + $crate::aux::ConstDeref>
        $feature_name<'a> for T {
            fn clone_boxed
                (&self)
                 -> Box<$feature_name<'a, Target = Self::Target> + 'a>
            {
                let cloned: T = self.clone();
                Box::new(cloned)
            }
        }
        impl<'a, S : 'a> Clone for Box<$feature_name<'a, Target = S> + 'a> {
            fn clone(&self) -> Self {
                $feature_name::clone_boxed(self)
            }
        }
    };

    ($(#[$meta:meta])* pub trait $feature_name:ident: $($req:ident),*) => {
        $(#[$meta])*
        pub trait $feature_name<'a>: $($req +)* $crate::aux::ConstDeref + 'a {
        }
        impl<'a, T : 'a + $($req +)* Clone + $crate::aux::ConstDeref>
        $feature_name<'a> for T {
        }
    };
}

supercow_features!(
    /// The default feature set for special `Supercow` references.
    pub trait DefaultFeatures: Clone);
supercow_features!(
    /// The feature set used for `ASupercow` references.
    pub trait SyncFeatures: Clone, Send, Sync);

pub struct Supercow<'a, OWNED,
                    SPECIAL = Box<DefaultFeatures<'a, Target = OWNED>>>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    // In order to implement `Deref` in a branch-free fashion that isn't
    // sensitive to the Supercow being moved, we set `ptr_mask` and
    // `ptr_displacement` such that
    // `target = &*((&self & ptr_mask) + ptr_displacement)`
    // (arithmetic in terms of bytes, obviously).
    //
    // So for the three cases:
    //
    // Owned => ptr_mask = ~0u, ptr_displacement = offsetof(self, Owned.0)
    // Borrowed, Special => ptr_mask = 0u, ptr_displacement = address
    ptr_mask: usize,
    ptr_displacement: usize,
    state: SupercowData<'a, OWNED, SPECIAL>,
}

enum SupercowData<'a, OWNED : 'a, SPECIAL> {
    Owned(OWNED),
    Borrowed(&'a OWNED),
    Special(SPECIAL),
}
use self::SupercowData::*;

impl<'a, OWNED, SPECIAL> Deref
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    type Target = OWNED;
    #[inline]
    fn deref(&self) -> &OWNED {
        unsafe {
            let self_address: usize = mem::transmute(self);
            mem::transmute((self_address & self.ptr_mask) +
                           self.ptr_displacement)
        }
    }
}

impl<'a, OWNED, SPECIAL>
Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    pub fn owned(inner: OWNED) -> Self {
        Self::from_data(Owned(inner))
    }

    pub fn borrowed(inner: &'a OWNED) -> Self {
        Self::from_data(Borrowed(inner))
    }

    pub fn special<T : Into<SPECIAL>>(inner: T) -> Self {
        Self::from_data(Special(inner.into()))
    }

    fn from_data(data: SupercowData<'a, OWNED, SPECIAL>) -> Self {
        let mut this = Supercow {
            ptr_mask: 0,
            ptr_displacement: 0,
            state: data,
        };

        let ptr = match this.state {
            Owned(ref r) => r as *const OWNED,
            Borrowed(r) => r as *const OWNED,
            Special(ref s) => s.const_deref() as *const OWNED,
        };
        this.set_ptr(ptr);

        this
    }

    fn set_ptr(&mut self, ptr: *const OWNED) {
        // Use relative addressing if `ptr` is inside `self` and absolute
        // addressing otherwise.
        //
        // Ordinarily, `ptr` will always be inside `self` if the state is
        // `Owned`, and outside otherwise. However, it is possible to create
        // `Borrow` implementations that return arbitrary pointers, so we
        // handle the two cases like this instead.
        let self_start = self as *const Self as usize;
        let self_end = self_start + mem::size_of::<Self>();
        let addr = ptr as usize;

        if addr >= self_start && addr < self_end {
            self.ptr_mask = !0;
            self.ptr_displacement = addr - self_start;
        } else {
            self.ptr_mask = 0;
            self.ptr_displacement = addr;
        }
    }
}

impl<'a, OWNED, SPECIAL> From<OWNED>
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn from(inner: OWNED) -> Self {
        Self::from_data(SupercowData::Owned(inner))
    }
}

impl<'a, OWNED, SPECIAL> From<&'a OWNED>
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn from(inner: &'a OWNED) -> Self {
        Self::from_data(SupercowData::Borrowed(inner))
    }
}

impl<'a, OWNED, SPECIAL>
Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a + Clone,
      SPECIAL : ConstDeref<Target = OWNED> {
    pub fn to_mut(&mut self) -> &mut OWNED {
        let new = match self.state {
            Owned(ref mut r) => return r,
            Borrowed(r) => Self::from(r.clone()),
            Special(ref s) => Self::from(s.const_deref().clone()),
        };
        *self = new;
        match self.state {
            Owned(ref mut r) => r,
            _ => unreachable!(),
        }
    }
}

impl<'a, OWNED, SPECIAL> Clone
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Clone + 'a,
      SPECIAL : Clone + ConstDeref<Target = OWNED> {
    fn clone(&self) -> Self {
        Supercow {
            ptr_mask: self.ptr_mask,
            ptr_displacement: self.ptr_displacement,
            state: match self.state {
                Owned(ref o) => Owned(o.clone()),
                Borrowed(r) => Borrowed(r),
                Special(ref s) => Special(s.clone()),
            }
        }
    }
}

macro_rules! deleg_fmt {
    ($tr:ident) => {
        impl<'a, OWNED, SPECIAL> fmt::$tr
        for Supercow<'a, OWNED, SPECIAL>
        where OWNED : fmt::$tr + 'a,
              SPECIAL : ConstDeref<Target = OWNED> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                (**self).fmt(f)
            }
        }
    }
}
deleg_fmt!(Binary);
deleg_fmt!(Debug);
deleg_fmt!(Display);
deleg_fmt!(LowerExp);
deleg_fmt!(LowerHex);
deleg_fmt!(Octal);
deleg_fmt!(Pointer);
deleg_fmt!(UpperExp);
deleg_fmt!(UpperHex);

impl<'a, OWNED, SPECIAL, T> cmp::PartialEq<T>
for Supercow<'a, OWNED, SPECIAL>
where T : Deref<Target = OWNED>,
      OWNED : PartialEq<OWNED> + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn eq(&self, other: &T) -> bool {
        **self == **other
    }

    fn ne(&self, other: &T) -> bool {
        **self != **other
    }
}

impl<'a, OWNED, SPECIAL> cmp::Eq
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Eq + 'a,
      SPECIAL : ConstDeref<Target = OWNED> { }

impl<'a, OWNED, SPECIAL, T> cmp::PartialOrd<T>
for Supercow<'a, OWNED, SPECIAL>
where T : Deref<Target = OWNED>,
      OWNED : PartialOrd<OWNED> + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
        (**self).partial_cmp(other)
    }

    fn lt(&self, other: &T) -> bool {
        **self < **other
    }

    fn le(&self, other: &T) -> bool {
        **self <= **other
    }

    fn gt(&self, other: &T) -> bool {
        **self > **other
    }

    fn ge(&self, other: &T) -> bool {
        **self >= **other
    }
}

impl<'a, OWNED, SPECIAL> cmp::Ord
for Supercow<'a, OWNED, SPECIAL>
where OWNED : cmp::Ord + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        (**self).cmp(other)
    }
}

impl<'a, OWNED, SPECIAL> Hash
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Hash + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn hash<H : Hasher>(&self, h: &mut H) {
        (**self).hash(h)
    }
}

fn doit() {
    let _x: Supercow<'static, u32> = Supercow::owned(42u32);
}
<commit_msg>Add a basic test.<commit_after>// Copyright 2016 Jason Lingle
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::convert::From;
use std::cmp;
use std::fmt;
use std::mem;
use std::hash::{Hash, Hasher};
use std::ops::Deref;

/// Miscelaneous things used to integrate other code with Supercow, but which
/// is not of interest to end users.
pub mod aux {
    use std::rc::Rc;
    use std::sync::Arc;

    /// Marker trait indicating a `Deref`-like which always returns the same
    /// reference.
    ///
    /// This is not indended for general use outside Supercow. Notably, `Box`
    /// and mundane references satisfy this trait's requirements, but
    /// deliberately do not implement it. It is also not a subtrait of `Deref`
    /// due to some additional special logic around boxes.
    ///
    /// ## Unsafety
    ///
    /// Behaviour is undefined if the implementation does not always return the
    /// same reference from `deref()` for any particular implementing value
    /// (including if that value is moved).
    pub unsafe trait ConstDeref {
        type Target : ?Sized;
        fn const_deref(&self) -> &Self::Target;
    }

    unsafe impl<T : ?Sized> ConstDeref for Rc<T> {
        type Target = T;
        fn const_deref(&self) -> &T { self }
    }

    unsafe impl<T : ?Sized> ConstDeref for Arc<T> {
        type Target = T;
        fn const_deref(&self) -> &T { self }
    }

    unsafe impl<T : ConstDeref + ?Sized> ConstDeref for Box<T> {
        type Target = T::Target;
        fn const_deref(&self) -> &T::Target {
            (**self).const_deref()
        }
    }
}

use self::aux::*;

/// Defines a "feature set" for a custom `Supercow` type.
///
/// ## Syntax
///
/// ```
/// #[macro_use] extern crate supercow;
///
/// # pub trait SomeTrait { }
/// # pub trait AnotherTrait { }
///
/// supercow_features!(
///   /// Some documentation, etc, if desired.
///   pub trait FeatureName: SomeTrait, AnotherTrait);
/// supercow_features!(
///   pub trait FeatureName2: Clone, SomeTrait, AnotherTrait);
///
/// # fn main() { }
/// ```
///
/// ## Semantics
///
/// A public trait named `FeatureName` is defined which extends all the listed
/// traits, other than `Clone`, and in addition to `ConstDeref`. If listed,
/// `Clone` *must* come first. If `Clone` is listed, the trait gains a
/// `clone_boxed()` method and `Box<FeatureName>` is `Clone`. All types which
/// implement all the listed traits (including `Clone`) and `ConstDeref`
/// implement `FeatureName`.
#[macro_export]
macro_rules! supercow_features {
    // It's unclear why $req:path doesn't work, but apparently constraints
    // allow neither `path` nor `ty`.
    ($(#[$meta:meta])* pub trait $feature_name:ident: Clone $(, $req:ident)*) => {
        $(#[$meta])*
        pub trait $feature_name<'a>: $($req +)* $crate::aux::ConstDeref + 'a {
            fn clone_boxed
                (&self)
                 -> Box<$feature_name<'a, Target = Self::Target> + 'a>;
        }
        impl<'a, T : 'a + $($req +)* Clone + $crate::aux::ConstDeref>
        $feature_name<'a> for T {
            fn clone_boxed
                (&self)
                 -> Box<$feature_name<'a, Target = Self::Target> + 'a>
            {
                let cloned: T = self.clone();
                Box::new(cloned)
            }
        }
        impl<'a, S : 'a> Clone for Box<$feature_name<'a, Target = S> + 'a> {
            fn clone(&self) -> Self {
                $feature_name::clone_boxed(&**self)
            }
        }
    };

    ($(#[$meta:meta])* pub trait $feature_name:ident: $($req:ident),*) => {
        $(#[$meta])*
        pub trait $feature_name<'a>: $($req +)* $crate::aux::ConstDeref + 'a {
        }
        impl<'a, T : 'a + $($req +)* Clone + $crate::aux::ConstDeref>
        $feature_name<'a> for T {
        }
    };
}

supercow_features!(
    /// The default feature set for special `Supercow` references.
    pub trait DefaultFeatures: Clone);
supercow_features!(
    /// The feature set used for `ASupercow` references.
    pub trait SyncFeatures: Clone, Send, Sync);

pub struct Supercow<'a, OWNED,
                    SPECIAL = Box<DefaultFeatures<'a, Target = OWNED>>>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    // In order to implement `Deref` in a branch-free fashion that isn't
    // sensitive to the Supercow being moved, we set `ptr_mask` and
    // `ptr_displacement` such that
    // `target = &*((&self & ptr_mask) + ptr_displacement)`
    // (arithmetic in terms of bytes, obviously).
    //
    // So for the three cases:
    //
    // Owned => ptr_mask = ~0u, ptr_displacement = offsetof(self, Owned.0)
    // Borrowed, Special => ptr_mask = 0u, ptr_displacement = address
    ptr_mask: usize,
    ptr_displacement: usize,
    state: SupercowData<'a, OWNED, SPECIAL>,
}

enum SupercowData<'a, OWNED : 'a, SPECIAL> {
    Owned(OWNED),
    Borrowed(&'a OWNED),
    Special(SPECIAL),
}
use self::SupercowData::*;

impl<'a, OWNED, SPECIAL> Deref
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    type Target = OWNED;
    #[inline]
    fn deref(&self) -> &OWNED {
        unsafe {
            let self_address: usize = mem::transmute(self);
            mem::transmute((self_address & self.ptr_mask) +
                           self.ptr_displacement)
        }
    }
}

impl<'a, OWNED, SPECIAL>
Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    pub fn owned(inner: OWNED) -> Self {
        Self::from_data(Owned(inner))
    }

    pub fn borrowed(inner: &'a OWNED) -> Self {
        Self::from_data(Borrowed(inner))
    }

    pub fn special<T : Into<SPECIAL>>(inner: T) -> Self {
        Self::from_data(Special(inner.into()))
    }

    fn from_data(data: SupercowData<'a, OWNED, SPECIAL>) -> Self {
        let mut this = Supercow {
            ptr_mask: 0,
            ptr_displacement: 0,
            state: data,
        };

        let ptr = match this.state {
            Owned(ref r) => r as *const OWNED,
            Borrowed(r) => r as *const OWNED,
            Special(ref s) => s.const_deref() as *const OWNED,
        };
        this.set_ptr(ptr);

        this
    }

    fn set_ptr(&mut self, ptr: *const OWNED) {
        // Use relative addressing if `ptr` is inside `self` and absolute
        // addressing otherwise.
        //
        // Ordinarily, `ptr` will always be inside `self` if the state is
        // `Owned`, and outside otherwise. However, it is possible to create
        // `Borrow` implementations that return arbitrary pointers, so we
        // handle the two cases like this instead.
        let self_start = self as *const Self as usize;
        let self_end = self_start + mem::size_of::<Self>();
        let addr = ptr as usize;

        if addr >= self_start && addr < self_end {
            self.ptr_mask = !0;
            self.ptr_displacement = addr - self_start;
        } else {
            self.ptr_mask = 0;
            self.ptr_displacement = addr;
        }
    }
}

impl<'a, OWNED, SPECIAL> From<OWNED>
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn from(inner: OWNED) -> Self {
        Self::from_data(SupercowData::Owned(inner))
    }
}

impl<'a, OWNED, SPECIAL> From<&'a OWNED>
for Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn from(inner: &'a OWNED) -> Self {
        Self::from_data(SupercowData::Borrowed(inner))
    }
}

impl<'a, OWNED, SPECIAL>
Supercow<'a, OWNED, SPECIAL>
where OWNED : 'a + Clone,
      SPECIAL : ConstDeref<Target = OWNED> {
    pub fn to_mut(&mut self) -> &mut OWNED {
        let new = match self.state {
            Owned(ref mut r) => return r,
            Borrowed(r) => Self::from(r.clone()),
            Special(ref s) => Self::from(s.const_deref().clone()),
        };
        *self = new;
        match self.state {
            Owned(ref mut r) => r,
            _ => unreachable!(),
        }
    }
}

impl<'a, OWNED, SPECIAL> Clone
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Clone + 'a,
      SPECIAL : Clone + ConstDeref<Target = OWNED> {
    fn clone(&self) -> Self {
        Supercow {
            ptr_mask: self.ptr_mask,
            ptr_displacement: self.ptr_displacement,
            state: match self.state {
                Owned(ref o) => Owned(o.clone()),
                Borrowed(r) => Borrowed(r),
                Special(ref s) => Special(s.clone()),
            }
        }
    }
}

macro_rules! deleg_fmt {
    ($tr:ident) => {
        impl<'a, OWNED, SPECIAL> fmt::$tr
        for Supercow<'a, OWNED, SPECIAL>
        where OWNED : fmt::$tr + 'a,
              SPECIAL : ConstDeref<Target = OWNED> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                (**self).fmt(f)
            }
        }
    }
}
deleg_fmt!(Binary);
deleg_fmt!(Debug);
deleg_fmt!(Display);
deleg_fmt!(LowerExp);
deleg_fmt!(LowerHex);
deleg_fmt!(Octal);
deleg_fmt!(Pointer);
deleg_fmt!(UpperExp);
deleg_fmt!(UpperHex);

impl<'a, OWNED, SPECIAL, T> cmp::PartialEq<T>
for Supercow<'a, OWNED, SPECIAL>
where T : Deref<Target = OWNED>,
      OWNED : PartialEq<OWNED> + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn eq(&self, other: &T) -> bool {
        **self == **other
    }

    fn ne(&self, other: &T) -> bool {
        **self != **other
    }
}

impl<'a, OWNED, SPECIAL> cmp::Eq
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Eq + 'a,
      SPECIAL : ConstDeref<Target = OWNED> { }

impl<'a, OWNED, SPECIAL, T> cmp::PartialOrd<T>
for Supercow<'a, OWNED, SPECIAL>
where T : Deref<Target = OWNED>,
      OWNED : PartialOrd<OWNED> + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
        (**self).partial_cmp(other)
    }

    fn lt(&self, other: &T) -> bool {
        **self < **other
    }

    fn le(&self, other: &T) -> bool {
        **self <= **other
    }

    fn gt(&self, other: &T) -> bool {
        **self > **other
    }

    fn ge(&self, other: &T) -> bool {
        **self >= **other
    }
}

impl<'a, OWNED, SPECIAL> cmp::Ord
for Supercow<'a, OWNED, SPECIAL>
where OWNED : cmp::Ord + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        (**self).cmp(other)
    }
}

impl<'a, OWNED, SPECIAL> Hash
for Supercow<'a, OWNED, SPECIAL>
where OWNED : Hash + 'a,
      SPECIAL : ConstDeref<Target = OWNED> {
    fn hash<H : Hasher>(&self, h: &mut H) {
        (**self).hash(h)
    }
}

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

    #[test]
    fn ref_to_owned() {
        let x = 42u32;
        let a: Supercow<u32> = Supercow::borrowed(&x);
        assert_eq!(x, *a);
        assert_eq!(&x as *const u32 as usize,
                   (&*a) as *const u32 as usize);

        let mut b = a.clone();
        assert_eq!(x, *b);
        assert_eq!(&x as *const u32 as usize,
                   (&*b) as *const u32 as usize);

        *b.to_mut() = 56;
        assert_eq!(42, *a);
        assert_eq!(x, *a);
        assert_eq!(&x as *const u32 as usize,
                   (&*a) as *const u32 as usize);
        assert_eq!(56, *b);
    }
}
<|endoftext|>