/*!

Miscellaneous helpers for common patterns.

*/

// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use cmp::Eq;

/// The identity function.
#[inline(always)]
pub pure fn id<T>(x: T) -> T { move x }

/// Ignores a value.
#[inline(always)]
pub pure fn ignore<T>(_x: T) { }

/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
/// original value of `*ptr`.
#[inline(always)]
pub fn with<T: Copy, R>(
    ptr: &mut T,
    new_value: T,
    op: &fn() -> R) -> R
{
    // NDM: if swap operator were defined somewhat differently,
    // we wouldn't need to copy...

    let old_value = *ptr;
    *ptr = move new_value;
    let result = op();
    *ptr = move old_value;
    return move result;
}

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline(always)]
pub fn swap<T>(x: &mut T, y: &mut T) {
    *x <-> *y;
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline(always)]
pub fn replace<T>(dest: &mut T, src: T) -> T {
    let mut tmp <- src;
    swap(dest, &mut tmp);
    move tmp
}

/// A non-copyable dummy type.
pub struct NonCopyable {
    i: (),
    drop { }
}

pub fn NonCopyable() -> NonCopyable { NonCopyable { i: () } }

/**
A utility function for indicating unreachable code. It will fail if
executed. This is occasionally useful to put after loops that never
terminate normally, but instead directly return from a function.

# Example

~~~
fn choose_weighted_item(v: &[Item]) -> Item {
    assert v.is_not_empty();
    let mut so_far = 0u;
    for v.each |item| {
        so_far += item.weight;
        if so_far > 100 {
            return item;
        }
    }
    // The above loop always returns, so we must hint to the
    // type checker that it isn't possible to get down here
    util::unreachable();
}
~~~

*/
pub fn unreachable() -> ! {
    fail ~"internal error: entered unreachable code";
}

mod tests {
    #[legacy_exports];
    #[test]
    fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[(5, false)];
        //FIXME #3387 assert x.eq(id(copy x));
        let y = copy x;
        assert x.eq(&id(y));
    }
    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert x == 42;
        assert y == 31337;
    }
    #[test]
    fn test_replace() {
        let mut x = Some(NonCopyable());
        let y = replace(&mut x, None);
        assert x.is_none();
        assert y.is_some();
    }
}
