<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

/*!

Operations on the ubiquitous `Option` type.

Type `Option` represents an optional value.

Every `Option<T>` value can either be `Some(T)` or `None`. Where in other
languages you might use a nullable type, in Rust you would use an option
type.

Options are most commonly used with pattern matching to query the presence
of a value and take action, always accounting for the `None` case.

# Example

~~~
let msg = Some(~"howdy");

// Take a reference to the contained string
match msg {
    Some(ref m) => io::println(m),
    None => ()
}

// Remove the contained string, destroying the Option
let unwrapped_msg = match move msg {
    Some(move m) => m,
    None => ~"default message"
};
~~~

*/

#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use cmp::Eq;
use option;
use ptr;
use str;
use util;

/// The option type
#[deriving_eq]
pub enum Option<T> {
    None,
    Some(T),
}

pub pure fn get<T: Copy>(opt: Option<T>) -> T {
    /*!
    Gets the value out of an option

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
    */

    match opt {
      Some(copy x) => return x,
      None => fail ~"option::get none"
    }
}

pub pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
    /*!
    Gets an immutable reference to the value inside an option.

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    match *opt {
        Some(ref x) => x,
        None => fail ~"option::get_ref none"
    }
}

pub pure fn map<T, U>(opt: &Option<T>, f: fn(x: &T) -> U) -> Option<U> {
    //! Maps a `some` value by reference from one type to another

    match *opt { Some(ref x) => Some(f(x)), None => None }
}

pub pure fn map_consume<T, U>(opt: Option<T>,
                              f: fn(v: T) -> U) -> Option<U> {
    /*!
     * As `map`, but consumes the option and gives `f` ownership to avoid
     * copying.
     */
    if opt.is_some() { Some(f(option::unwrap(move opt))) } else { None }
}

pub pure fn chain<T, U>(opt: Option<T>,
                        f: fn(t: T) -> Option<U>) -> Option<U> {
    /*!
     * Update an optional value by optionally running its content through a
     * function that returns an option.
     */

    match move opt {
        Some(move t) => f(move t),
        None => None
    }
}

pub pure fn chain_ref<T, U>(opt: &Option<T>,
                            f: fn(x: &T) -> Option<U>) -> Option<U> {
    /*!
     * Update an optional value by optionally running its content by reference
     * through a function that returns an option.
     */

    match *opt { Some(ref x) => f(x), None => None }
}

pub pure fn or<T>(opta: Option<T>, optb: Option<T>) -> Option<T> {
    /*!
     * Returns the leftmost some() value, or none if both are none.
     */
    match move opta {
        Some(move opta) => Some(move opta),
        _ => move optb
    }
}

#[inline(always)]
pub pure fn while_some<T>(x: Option<T>, blk: fn(v: T) -> Option<T>) {
    //! Applies a function zero or more times until the result is none.

    let mut opt = move x;
    while opt.is_some() {
        opt = blk(unwrap(move opt));
    }
}

pub pure fn is_none<T>(opt: &Option<T>) -> bool {
    //! Returns true if the option equals `none`

    match *opt { None => true, Some(_) => false }
}

pub pure fn is_some<T>(opt: &Option<T>) -> bool {
    //! Returns true if the option contains some value

    !is_none(opt)
}

pub pure fn get_default<T: Copy>(opt: Option<T>, def: T) -> T {
    //! Returns the contained value or a default

    match opt { Some(copy x) => x, None => def }
}

pub pure fn map_default<T, U>(opt: &Option<T>, def: U,
                              f: fn(x: &T) -> U) -> U {
    //! Applies a function to the contained value or returns a default

    match *opt { None => move def, Some(ref t) => f(t) }
}

pub pure fn iter<T>(opt: &Option<T>, f: fn(x: &T)) {
    //! Performs an operation on the contained value by reference
    match *opt { None => (), Some(ref t) => f(t) }
}

#[inline(always)]
pub pure fn unwrap<T>(opt: Option<T>) -> T {
    /*!
    Moves a value out of an option type and returns it.

    Useful primarily for getting strings, vectors and unique pointers out
    of option types without copying them.

    # Failure

    Fails if the value equals `None`.

    # Safety note

    In general, because this function may fail, its use is discouraged.
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    match move opt {
        Some(move x) => move x,
        None => fail ~"option::unwrap none"
    }
}

#[inline(always)]
pub fn swap_unwrap<T>(opt: &mut Option<T>) -> T {
    /*!
    The option dance. Moves a value out of an option type and returns it,
    replacing the original with `None`.

    # Failure

    Fails if the value equals `None`.
     */
    if opt.is_none() { fail ~"option::swap_unwrap none" }
    unwrap(util::replace(opt, None))
}

pub pure fn expect<T>(opt: Option<T>, reason: &str) -> T {
    //! As unwrap, but with a specified failure message.
    match move opt {
        Some(move val) => val,
        None => fail reason.to_owned(),
    }
}

impl<T> Option<T> {
    /// Returns true if the option equals `none`
    #[inline(always)]
    pure fn is_none(&self) -> bool { is_none(self) }

    /// Returns true if the option contains some value
    #[inline(always)]
    pure fn is_some(&self) -> bool { is_some(self) }

    /**
     * Update an optional value by optionally running its content by reference
     * through a function that returns an option.
     */
    #[inline(always)]
    pure fn chain_ref<U>(&self, f: fn(x: &T) -> Option<U>) -> Option<U> {
        chain_ref(self, f)
    }

    /// Maps a `some` value from one type to another by reference
    #[inline(always)]
    pure fn map<U>(&self, f: fn(x: &T) -> U) -> Option<U> { map(self, f) }

    /// Applies a function to the contained value or returns a default
    #[inline(always)]
    pure fn map_default<U>(&self, def: U, f: fn(x: &T) -> U) -> U {
        map_default(self, move def, f)
    }

    /// Performs an operation on the contained value by reference
    #[inline(always)]
    pure fn iter(&self, f: fn(x: &T)) { iter(self, f) }

    /**
    Gets an immutable reference to the value inside an option.

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    #[inline(always)]
    pure fn get_ref(&self) -> &self/T { get_ref(self) }

    /**
     * Gets the value out of an option without copying.
     *
     * # Failure
     *
     * Fails if the value equals `none`
     */
    #[inline(always)]
    pure fn unwrap(self) -> T { unwrap(self) }

    /**
     * Gets the value out of an option, printing a specified message on
     * failure
     *
     * # Failure
     *
     * Fails if the value equals `none`
     */
    #[inline(always)]
    pure fn expect(self, reason: &str) -> T { expect(self, reason) }
}

impl<T: Copy> Option<T> {
    /**
    Gets the value out of an option

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
    */
    #[inline(always)]
    pure fn get(self) -> T { get(self) }

    #[inline(always)]
    pure fn get_default(self, def: T) -> T { get_default(self, def) }

    /// Applies a function zero or more times until the result is none.
    #[inline(always)]
    pure fn while_some(self, blk: fn(v: T) -> Option<T>) {
        while_some(self, blk)
    }
}

#[test]
fn test_unwrap_ptr() {
    let x = ~0;
    let addr_x = ptr::addr_of(&(*x));
    let opt = Some(move x);
    let y = unwrap(move opt);
    let addr_y = ptr::addr_of(&(*y));
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_str() {
    let x = ~"test";
    let addr_x = str::as_buf(x, |buf, _len| buf);
    let opt = Some(move x);
    let y = unwrap(move opt);
    let addr_y = str::as_buf(y, |buf, _len| buf);
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_resource() {
    struct R {
       i: @mut int,
       drop { *(self.i) += 1; }
    }

    fn R(i: @mut int) -> R {
        R {
            i: i
        }
    }

    let i = @mut 0;
    {
        let x = R(i);
        let opt = Some(move x);
        let _y = unwrap(move opt);
    }
    assert *i == 1;
}

#[test]
fn test_option_dance() {
    let x = Some(());
    let mut y = Some(5);
    let mut y2 = 0;
    do x.iter |_x| {
        y2 = swap_unwrap(&mut y);
    }
    assert y2 == 5;
    assert y.is_none();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_option_too_much_dance() {
    let mut y = Some(util::NonCopyable());
    let _y2 = swap_unwrap(&mut y);
    let _y3 = swap_unwrap(&mut y);
}

#[test]
fn test_option_while_some() {
    let mut i = 0;
    do Some(10).while_some |j| {
        i += 1;
        if (j > 0) {
            Some(j-1)
        } else {
            None
        }
    }
    assert i == 11;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Add option::get_zero<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

/*!

Operations on the ubiquitous `Option` type.

Type `Option` represents an optional value.

Every `Option<T>` value can either be `Some(T)` or `None`. Where in other
languages you might use a nullable type, in Rust you would use an option
type.

Options are most commonly used with pattern matching to query the presence
of a value and take action, always accounting for the `None` case.

# Example

~~~
let msg = Some(~"howdy");

// Take a reference to the contained string
match msg {
    Some(ref m) => io::println(m),
    None => ()
}

// Remove the contained string, destroying the Option
let unwrapped_msg = match move msg {
    Some(move m) => m,
    None => ~"default message"
};
~~~

*/

#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

use cmp::Eq;
use option;
use ptr;
use str;
use util;
use num::Zero;

/// The option type
#[deriving_eq]
pub enum Option<T> {
    None,
    Some(T),
}

pub pure fn get<T: Copy>(opt: Option<T>) -> T {
    /*!
    Gets the value out of an option

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
    */

    match opt {
      Some(copy x) => return x,
      None => fail ~"option::get none"
    }
}

pub pure fn get_ref<T>(opt: &r/Option<T>) -> &r/T {
    /*!
    Gets an immutable reference to the value inside an option.

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    match *opt {
        Some(ref x) => x,
        None => fail ~"option::get_ref none"
    }
}

pub pure fn map<T, U>(opt: &Option<T>, f: fn(x: &T) -> U) -> Option<U> {
    //! Maps a `some` value by reference from one type to another

    match *opt { Some(ref x) => Some(f(x)), None => None }
}

pub pure fn map_consume<T, U>(opt: Option<T>,
                              f: fn(v: T) -> U) -> Option<U> {
    /*!
     * As `map`, but consumes the option and gives `f` ownership to avoid
     * copying.
     */
    if opt.is_some() { Some(f(option::unwrap(move opt))) } else { None }
}

pub pure fn chain<T, U>(opt: Option<T>,
                        f: fn(t: T) -> Option<U>) -> Option<U> {
    /*!
     * Update an optional value by optionally running its content through a
     * function that returns an option.
     */

    match move opt {
        Some(move t) => f(move t),
        None => None
    }
}

pub pure fn chain_ref<T, U>(opt: &Option<T>,
                            f: fn(x: &T) -> Option<U>) -> Option<U> {
    /*!
     * Update an optional value by optionally running its content by reference
     * through a function that returns an option.
     */

    match *opt { Some(ref x) => f(x), None => None }
}

pub pure fn or<T>(opta: Option<T>, optb: Option<T>) -> Option<T> {
    /*!
     * Returns the leftmost some() value, or none if both are none.
     */
    match move opta {
        Some(move opta) => Some(move opta),
        _ => move optb
    }
}

#[inline(always)]
pub pure fn while_some<T>(x: Option<T>, blk: fn(v: T) -> Option<T>) {
    //! Applies a function zero or more times until the result is none.

    let mut opt = move x;
    while opt.is_some() {
        opt = blk(unwrap(move opt));
    }
}

pub pure fn is_none<T>(opt: &Option<T>) -> bool {
    //! Returns true if the option equals `none`

    match *opt { None => true, Some(_) => false }
}

pub pure fn is_some<T>(opt: &Option<T>) -> bool {
    //! Returns true if the option contains some value

    !is_none(opt)
}

pub pure fn get_zero<T: Copy Zero>(opt: Option<T>) -> T {
    //! Returns the contained value or zero (for this type)

    match opt { Some(copy x) => x, None => Zero::zero() }
}

pub pure fn get_default<T: Copy>(opt: Option<T>, def: T) -> T {
    //! Returns the contained value or a default

    match opt { Some(copy x) => x, None => def }
}

pub pure fn map_default<T, U>(opt: &Option<T>, def: U,
                              f: fn(x: &T) -> U) -> U {
    //! Applies a function to the contained value or returns a default

    match *opt { None => move def, Some(ref t) => f(t) }
}

pub pure fn iter<T>(opt: &Option<T>, f: fn(x: &T)) {
    //! Performs an operation on the contained value by reference
    match *opt { None => (), Some(ref t) => f(t) }
}

#[inline(always)]
pub pure fn unwrap<T>(opt: Option<T>) -> T {
    /*!
    Moves a value out of an option type and returns it.

    Useful primarily for getting strings, vectors and unique pointers out
    of option types without copying them.

    # Failure

    Fails if the value equals `None`.

    # Safety note

    In general, because this function may fail, its use is discouraged.
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    match move opt {
        Some(move x) => move x,
        None => fail ~"option::unwrap none"
    }
}

#[inline(always)]
pub fn swap_unwrap<T>(opt: &mut Option<T>) -> T {
    /*!
    The option dance. Moves a value out of an option type and returns it,
    replacing the original with `None`.

    # Failure

    Fails if the value equals `None`.
     */
    if opt.is_none() { fail ~"option::swap_unwrap none" }
    unwrap(util::replace(opt, None))
}

pub pure fn expect<T>(opt: Option<T>, reason: &str) -> T {
    //! As unwrap, but with a specified failure message.
    match move opt {
        Some(move val) => val,
        None => fail reason.to_owned(),
    }
}

impl<T> Option<T> {
    /// Returns true if the option equals `none`
    #[inline(always)]
    pure fn is_none(&self) -> bool { is_none(self) }

    /// Returns true if the option contains some value
    #[inline(always)]
    pure fn is_some(&self) -> bool { is_some(self) }

    /**
     * Update an optional value by optionally running its content by reference
     * through a function that returns an option.
     */
    #[inline(always)]
    pure fn chain_ref<U>(&self, f: fn(x: &T) -> Option<U>) -> Option<U> {
        chain_ref(self, f)
    }

    /// Maps a `some` value from one type to another by reference
    #[inline(always)]
    pure fn map<U>(&self, f: fn(x: &T) -> U) -> Option<U> { map(self, f) }

    /// Applies a function to the contained value or returns a default
    #[inline(always)]
    pure fn map_default<U>(&self, def: U, f: fn(x: &T) -> U) -> U {
        map_default(self, move def, f)
    }

    /// Performs an operation on the contained value by reference
    #[inline(always)]
    pure fn iter(&self, f: fn(x: &T)) { iter(self, f) }

    /**
    Gets an immutable reference to the value inside an option.

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
     */
    #[inline(always)]
    pure fn get_ref(&self) -> &self/T { get_ref(self) }

    /**
     * Gets the value out of an option without copying.
     *
     * # Failure
     *
     * Fails if the value equals `none`
     */
    #[inline(always)]
    pure fn unwrap(self) -> T { unwrap(self) }

    /**
     * Gets the value out of an option, printing a specified message on
     * failure
     *
     * # Failure
     *
     * Fails if the value equals `none`
     */
    #[inline(always)]
    pure fn expect(self, reason: &str) -> T { expect(self, reason) }
}

impl<T: Copy> Option<T> {
    /**
    Gets the value out of an option

    # Failure

    Fails if the value equals `None`

    # Safety note

    In general, because this function may fail, its use is discouraged
    (calling `get` on `None` is akin to dereferencing a null pointer).
    Instead, prefer to use pattern matching and handle the `None`
    case explicitly.
    */
    #[inline(always)]
    pure fn get(self) -> T { get(self) }

    #[inline(always)]
    pure fn get_default(self, def: T) -> T { get_default(self, def) }

    /// Applies a function zero or more times until the result is none.
    #[inline(always)]
    pure fn while_some(self, blk: fn(v: T) -> Option<T>) {
        while_some(self, blk)
    }
}

impl<T: Copy Zero> Option<T> {
    #[inline(always)]
    pure fn get_zero(self) -> T { get_zero(self) }
}

#[test]
fn test_unwrap_ptr() {
    let x = ~0;
    let addr_x = ptr::addr_of(&(*x));
    let opt = Some(move x);
    let y = unwrap(move opt);
    let addr_y = ptr::addr_of(&(*y));
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_str() {
    let x = ~"test";
    let addr_x = str::as_buf(x, |buf, _len| buf);
    let opt = Some(move x);
    let y = unwrap(move opt);
    let addr_y = str::as_buf(y, |buf, _len| buf);
    assert addr_x == addr_y;
}

#[test]
fn test_unwrap_resource() {
    struct R {
       i: @mut int,
       drop { *(self.i) += 1; }
    }

    fn R(i: @mut int) -> R {
        R {
            i: i
        }
    }

    let i = @mut 0;
    {
        let x = R(i);
        let opt = Some(move x);
        let _y = unwrap(move opt);
    }
    assert *i == 1;
}

#[test]
fn test_option_dance() {
    let x = Some(());
    let mut y = Some(5);
    let mut y2 = 0;
    do x.iter |_x| {
        y2 = swap_unwrap(&mut y);
    }
    assert y2 == 5;
    assert y.is_none();
}
#[test] #[should_fail] #[ignore(cfg(windows))]
fn test_option_too_much_dance() {
    let mut y = Some(util::NonCopyable());
    let _y2 = swap_unwrap(&mut y);
    let _y3 = swap_unwrap(&mut y);
}

#[test]
fn test_option_while_some() {
    let mut i = 0;
    do Some(10).while_some |j| {
        i += 1;
        if (j > 0) {
            Some(j-1)
        } else {
            None
        }
    }
    assert i == 11;
}

#[test]
fn test_get_zero() {
    let some_stuff = Some(42);
    assert some_stuff.get_zero() == 42;
    let no_stuff: Option<int> = None;
    assert no_stuff.get_zero() == 0;
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


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

trait ToStr { fn to_str() -> ~str; }

impl int: ToStr {
    fn to_str() -> ~str { int::str(self) }
}
impl i8: ToStr {
    fn to_str() -> ~str { i8::str(self) }
}
impl i16: ToStr {
    fn to_str() -> ~str { i16::str(self) }
}
impl i32: ToStr {
    fn to_str() -> ~str { i32::str(self) }
}
impl i64: ToStr {
    fn to_str() -> ~str { i64::str(self) }
}
impl uint: ToStr {
    fn to_str() -> ~str { uint::str(self) }
}
impl u8: ToStr {
    fn to_str() -> ~str { u8::str(self) }
}
impl u16: ToStr {
    fn to_str() -> ~str { u16::str(self) }
}
impl u32: ToStr {
    fn to_str() -> ~str { u32::str(self) }
}
impl u64: ToStr {
    fn to_str() -> ~str { u64::str(self) }
}
impl float: ToStr {
    fn to_str() -> ~str { float::to_str(self, 4u) }
}
impl bool: ToStr {
    fn to_str() -> ~str { bool::to_str(self) }
}
impl (): ToStr {
    fn to_str() -> ~str { ~"()" }
}
impl ~str: ToStr {
    fn to_str() -> ~str { self }
}

impl<A: ToStr copy, B: ToStr copy> (A, B): ToStr {
    fn to_str() -> ~str {
        let (a, b) = self;
        ~"(" + a.to_str() + ~", " + b.to_str() + ~")"
    }
}
impl<A: ToStr copy, B: ToStr copy, C: ToStr copy> (A, B, C): ToStr {
    fn to_str() -> ~str {
        let (a, b, c) = self;
        ~"(" + a.to_str() + ~", " + b.to_str() + ~", " + c.to_str() + ~")"
    }
}

impl<A: ToStr> ~[A]: ToStr {
    fn to_str() -> ~str {
        let mut acc = ~"[", first = true;
        for vec::each(self) |elt| {
            if first { first = false; }
            else { str::push_str(acc, ~", "); }
            str::push_str(acc, elt.to_str());
        }
        str::push_char(acc, ']');
        acc
    }
}

impl<A: ToStr> @A: ToStr {
    fn to_str() -> ~str { ~"@" + (*self).to_str() }
}
impl<A: ToStr> ~A: ToStr {
    fn to_str() -> ~str { ~"~" + (*self).to_str() }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_simple_types() {
        assert 1.to_str() == ~"1";
        assert (-1).to_str() == ~"-1";
        assert 200u.to_str() == ~"200";
        assert 2u8.to_str() == ~"2";
        assert true.to_str() == ~"true";
        assert false.to_str() == ~"false";
        assert ().to_str() == ~"()";
        assert (~"hi").to_str() == ~"hi";
    }

    #[test]
    fn test_tuple_types() {
        assert (1, 2).to_str() == ~"(1, 2)";
        assert (~"a", ~"b", false).to_str() == ~"(a, b, false)";
        assert ((), ((), 100)).to_str() == ~"((), ((), 100))";
    }

    #[test]
    #[ignore]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert x.to_str() == ~"~[]";
        assert (~[1]).to_str() == ~"~[1]";
        assert (~[1, 2, 3]).to_str() == ~"~[1, 2, 3]";
        assert (~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"~[~[], ~[1], ~[1, 1]]";
    }

    #[test]
    fn test_pointer_types() {
        assert (@1).to_str() == ~"@1";
        assert (~(true, false)).to_str() == ~"~(true, false)";
    }
}
<commit_msg>libcore: Add an implementation of to_str for &str.<commit_after>// NB: transitionary, de-mode-ing.
#[forbid(deprecated_mode)];
#[forbid(deprecated_pattern)];

trait ToStr { fn to_str() -> ~str; }

impl int: ToStr {
    fn to_str() -> ~str { int::str(self) }
}
impl i8: ToStr {
    fn to_str() -> ~str { i8::str(self) }
}
impl i16: ToStr {
    fn to_str() -> ~str { i16::str(self) }
}
impl i32: ToStr {
    fn to_str() -> ~str { i32::str(self) }
}
impl i64: ToStr {
    fn to_str() -> ~str { i64::str(self) }
}
impl uint: ToStr {
    fn to_str() -> ~str { uint::str(self) }
}
impl u8: ToStr {
    fn to_str() -> ~str { u8::str(self) }
}
impl u16: ToStr {
    fn to_str() -> ~str { u16::str(self) }
}
impl u32: ToStr {
    fn to_str() -> ~str { u32::str(self) }
}
impl u64: ToStr {
    fn to_str() -> ~str { u64::str(self) }
}
impl float: ToStr {
    fn to_str() -> ~str { float::to_str(self, 4u) }
}
impl bool: ToStr {
    fn to_str() -> ~str { bool::to_str(self) }
}
impl (): ToStr {
    fn to_str() -> ~str { ~"()" }
}
impl ~str: ToStr {
    fn to_str() -> ~str { self }
}
impl &str: ToStr {
    fn to_str() -> ~str { str::from_slice(self) }
}

impl<A: ToStr copy, B: ToStr copy> (A, B): ToStr {
    fn to_str() -> ~str {
        let (a, b) = self;
        ~"(" + a.to_str() + ~", " + b.to_str() + ~")"
    }
}
impl<A: ToStr copy, B: ToStr copy, C: ToStr copy> (A, B, C): ToStr {
    fn to_str() -> ~str {
        let (a, b, c) = self;
        ~"(" + a.to_str() + ~", " + b.to_str() + ~", " + c.to_str() + ~")"
    }
}

impl<A: ToStr> ~[A]: ToStr {
    fn to_str() -> ~str {
        let mut acc = ~"[", first = true;
        for vec::each(self) |elt| {
            if first { first = false; }
            else { str::push_str(acc, ~", "); }
            str::push_str(acc, elt.to_str());
        }
        str::push_char(acc, ']');
        acc
    }
}

impl<A: ToStr> @A: ToStr {
    fn to_str() -> ~str { ~"@" + (*self).to_str() }
}
impl<A: ToStr> ~A: ToStr {
    fn to_str() -> ~str { ~"~" + (*self).to_str() }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_simple_types() {
        assert 1.to_str() == ~"1";
        assert (-1).to_str() == ~"-1";
        assert 200u.to_str() == ~"200";
        assert 2u8.to_str() == ~"2";
        assert true.to_str() == ~"true";
        assert false.to_str() == ~"false";
        assert ().to_str() == ~"()";
        assert (~"hi").to_str() == ~"hi";
    }

    #[test]
    fn test_tuple_types() {
        assert (1, 2).to_str() == ~"(1, 2)";
        assert (~"a", ~"b", false).to_str() == ~"(a, b, false)";
        assert ((), ((), 100)).to_str() == ~"((), ((), 100))";
    }

    #[test]
    #[ignore]
    fn test_vectors() {
        let x: ~[int] = ~[];
        assert x.to_str() == ~"~[]";
        assert (~[1]).to_str() == ~"~[1]";
        assert (~[1, 2, 3]).to_str() == ~"~[1, 2, 3]";
        assert (~[~[], ~[1], ~[1, 1]]).to_str() ==
               ~"~[~[], ~[1], ~[1, 1]]";
    }

    #[test]
    fn test_pointer_types() {
        assert (@1).to_str() == ~"@1";
        assert (~(true, false)).to_str() == ~"~(true, false)";
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

/*!

The standard module imported by default into all Rust modules

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default. The prelude imports various core parts of the library that are
generally useful to many Rust programs.

*/

// Reexported core operators
pub use kinds::{Freeze, Pod, Send, Sized, Share};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop, Deref, DerefMut};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use from_str::from_str;
pub use iter::range;
pub use mem::drop;

// Reexported types and traits

pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes};
pub use c_str::ToCStr;
pub use char::Char;
pub use clone::Clone;
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use iter::{FromIterator, Extendable};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Signed, Unsigned, Round};
pub use num::{Primitive, Int, Float, ToPrimitive, FromPrimitive};
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
pub use ptr::RawPtr;
pub use io::{Buffer, Writer, Reader, Seek};
pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
pub use to_str::{ToStr, IntoStr};
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCloneableVector};
pub use slice::{OwnedVector, OwnedCloneableVector, OwnedEqVector};
pub use slice::{MutableVector, MutableTotalOrdVector};
pub use slice::{Vector, VectorVector, CloneableVector, ImmutableVector};

// Reexported runtime types
pub use comm::{channel, Sender, Receiver};
pub use task::spawn;

// Reexported statics
#[cfg(not(test))]
pub use gc::GC;
<commit_msg>std: Add Vec to the prelude<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

/*!

The standard module imported by default into all Rust modules

Many programming languages have a 'prelude': a particular subset of the
libraries that come with the language. Every program imports the prelude by
default. The prelude imports various core parts of the library that are
generally useful to many Rust programs.

*/

// Reexported core operators
pub use kinds::{Freeze, Pod, Send, Sized, Share};
pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not};
pub use ops::{BitAnd, BitOr, BitXor};
pub use ops::{Drop, Deref, DerefMut};
pub use ops::{Shl, Shr, Index};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use from_str::from_str;
pub use iter::range;
pub use mem::drop;

// Reexported types and traits

pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes};
pub use c_str::ToCStr;
pub use char::Char;
pub use clone::Clone;
pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv};
pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
pub use iter::{FromIterator, Extendable};
pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator};
pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Signed, Unsigned, Round};
pub use num::{Primitive, Int, Float, ToPrimitive, FromPrimitive};
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
pub use ptr::RawPtr;
pub use io::{Buffer, Writer, Reader, Seek};
pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
pub use to_str::{ToStr, IntoStr};
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12};
pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector, ImmutableCloneableVector};
pub use slice::{OwnedVector, OwnedCloneableVector, OwnedEqVector};
pub use slice::{MutableVector, MutableTotalOrdVector};
pub use slice::{Vector, VectorVector, CloneableVector, ImmutableVector};
pub use vec::Vec;

// Reexported runtime types
pub use comm::{channel, Sender, Receiver};
pub use task::spawn;

// Reexported statics
#[cfg(not(test))]
pub use gc::GC;
<|endoftext|>


<commit_before>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::thread::{self, JoinHandle};

use crate::{constants::*, refiner};
use regex::Regex;
use threadpool::ThreadPool;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> =
        vec![("diff ", FAINT), ("index ", FAINT), ("Binary files ", BOLD)];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> Option<&str> {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return Some(static_header_prefix.1);
        }
    }

    return None;
}

fn print<W: io::Write + Send>(stream: &mut BufWriter<W>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

/**
A StringFuture can perform diffing in a background thread.

Doing get() on a future that isn't done yet will block until the result is
available.
*/
struct StringFuture {
    // This field is only valid if we're done with the result_receiver (next
    // field)
    result: String,

    // If available, get() will await a result on this receiver, then populate
    // the result field and return it
    result_receiver: Option<Receiver<String>>,
}

impl StringFuture {
    /// Create an already-finished future
    pub fn from_string(result: String) -> StringFuture {
        return StringFuture {
            result,
            result_receiver: None,
        };
    }

    /// Call get() to get the result of this diff
    pub fn from_oldnew(
        old_text: String,
        new_text: String,
        thread_pool: &ThreadPool,
    ) -> StringFuture {
        // Create a String channel
        let (sender, receiver): (SyncSender<String>, Receiver<String>) = sync_channel(1);

        // Start diffing in a thread
        thread_pool.execute(move || {
            let mut result = String::new();
            for line in refiner::format(&old_text, &new_text) {
                result.push_str(&line);
                result.push('\n');
            }

            // Done, channel the result!
            sender.send(result).unwrap();
        });

        return StringFuture {
            result: "".to_string(),
            result_receiver: Some(receiver),
        };
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn is_empty(&mut self) -> bool {
        return self.get().is_empty();
    }

    pub fn get(&mut self) -> &str {
        // If the result is still pending...
        if let Some(receiver) = &self.result_receiver {
            // ... wait for it
            self.result = receiver.recv().unwrap();
            self.result_receiver = None;
        }

        return &self.result;
    }
}

/**
The way this thing works from the outside is that you initialize it with an
output stream, you pass it one line of input at a time, and it writes
formatted lines to the output stream.

From the inside, it will collect blocks of either diff lines or not-diff-lines.

The not-diff-lines blocks will be enqueued for printing by the printing thread.

The diff lines blocks will also be enqueued for printing, but the actual diffing
will happen in background threads.
*/
pub struct LineCollector {
    old_text: String,
    new_text: String,
    plain_text: String,
    consumer_thread: Option<JoinHandle<()>>,

    diffing_threads: ThreadPool,

    // FIXME: I'd rather have had a SyncSender of some trait here. That would
    // enable us to have two separate result implementations, one which just
    // returns a string and another that does a background computation first.
    // But I failed to figure out how when I tried, more Googling needed!
    queue_putter: SyncSender<StringFuture>,
}

impl Drop for LineCollector {
    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();

        // Tell the consumer thread to drain and quit. Sending an empty string
        // like this is the secret handshake for requesting a shutdown.
        self.queue_putter
            .send(StringFuture::from_string("".to_string()))
            .unwrap();

        // Wait for the consumer thread to finish
        // https://stackoverflow.com/q/57670145/473672
        self.consumer_thread.take().map(JoinHandle::join);
    }
}

impl LineCollector {
    pub fn new<W: io::Write + Send + 'static>(output: W) -> LineCollector {
        // This is how many entries we can look ahead. An "entry" in this case
        // being either a plain text section or an oldnew section.
        //
        // Benchmark timings with different multipliers on an 8 logical cores
        // machine with a 6.6M lines / 208MB diff:
        //
        // 500x => 5.68s  <-- Not much better than 100x
        // 100x => 5.71s  <-- Somewhat better than 50x
        //  50x => 5.98s
        //  10x >= 7.41s  <-- Much worse than 50x
        let queue_size = num_cpus::get() * 100;

        // Allocate a queue where we can push our futures to the consumer thread
        let (queue_putter, queue_getter): (SyncSender<StringFuture>, Receiver<StringFuture>) =
            sync_channel(queue_size);

        // This thread takes futures and prints their results
        let thread_builder = thread::Builder::new().name("Output Printer Thread".to_string());
        let consumer = thread_builder
            .spawn(move || {
                let mut output = BufWriter::new(output);

                loop {
                    if let Ok(mut print_me) = queue_getter.recv() {
                        if print_me.is_empty() {
                            // Secret handshake received, done!
                            break;
                        }
                        print(&mut output, print_me.get());
                    }
                }
            })
            .unwrap();

        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            consumer_thread: Some(consumer),
            diffing_threads: ThreadPool::new(num_cpus::get()),
            queue_putter,
        };
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        self.queue_putter
            .send(StringFuture::from_oldnew(
                self.old_text.clone(),
                self.new_text.clone(),
                &self.diffing_threads,
            ))
            .unwrap();

        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        // Enqueue an already-resolved future
        self.queue_putter
            .send(StringFuture::from_string(String::from(&self.plain_text)))
            .unwrap();

        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    /// Like consume_plain_line(), but without outputting any trailing linefeed.
    fn consume_plain_linepart(&mut self, linepart: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(linepart);
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..]);
        self.old_text.push('\n');
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..]);
        self.new_text.push('\n');
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_plusminus_header(&mut self, line: &str) {
        self.consume_plain_linepart(BOLD);

        if let Some(last_tab_index) = line.rfind('\t') {
            self.consume_plain_linepart(&line[..last_tab_index]);

            // When I ran plain "diff" (no git involved), this trailing part
            // contained very precise file timestamps. I don't think those
            // provide much value, so let's faint them out.
            self.consume_plain_linepart(FAINT);
            self.consume_plain_linepart(&line[last_tab_index..]);
        } else {
            self.consume_plain_linepart(line);
        }

        self.consume_plain_line(NORMAL);
    }

    fn consume_hunk_header(&mut self, line: &str) {
        self.consume_plain_linepart(HUNK_HEADER);

        if let Some(second_atat_index) = line.find(" @@ ") {
            // Highlight the function name
            self.consume_plain_linepart(FAINT);
            self.consume_plain_linepart(&line[..(second_atat_index + 4)]);
            self.consume_plain_linepart(BOLD);
            self.consume_plain_linepart(&line[(second_atat_index + 4)..]);
        } else {
            self.consume_plain_linepart(line);
        }

        self.consume_plain_line(NORMAL);
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        if let Some(fixed_highlight) = get_fixed_highlight(&line) {
            self.consume_plain_linepart(fixed_highlight);
            self.consume_plain_linepart(&line);
            self.consume_plain_line(NORMAL); // consume_plain_line() will add a linefeed to the output
            return;
        }

        if line.starts_with("---") || line.starts_with("+++") {
            self.consume_plusminus_header(&line);
            return;
        }

        if line.starts_with("@@ ") {
            self.consume_hunk_header(&line);
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<commit_msg>Set copy / rename highlights<commit_after>use crate::io::ErrorKind;
use std::io::{self, BufWriter, Write};
use std::process::exit;
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
use std::thread::{self, JoinHandle};

use crate::{constants::*, refiner};
use regex::Regex;
use threadpool::ThreadPool;

const HUNK_HEADER: &str = "\x1b[36m"; // Cyan

lazy_static! {
    static ref STATIC_HEADER_PREFIXES: Vec<(&'static str, &'static str)> = vec![
        ("diff ", FAINT),
        ("index ", FAINT),
        ("Binary files ", BOLD),
        ("copy from ", FAINT),
        ("copy to ", BOLD),
        ("rename from ", FAINT),
        ("rename to ", BOLD),
        ("similarity index ", FAINT),
        ("new file mode ", FAINT),
    ];
    static ref ANSI_COLOR_REGEX: Regex = Regex::new("\x1b[^m]*m").unwrap();
}

#[must_use]
fn get_fixed_highlight(line: &str) -> Option<&str> {
    for static_header_prefix in STATIC_HEADER_PREFIXES.iter() {
        let prefix = static_header_prefix.0;
        if line.starts_with(prefix) {
            return Some(static_header_prefix.1);
        }
    }

    return None;
}

fn print<W: io::Write + Send>(stream: &mut BufWriter<W>, text: &str) {
    if let Err(error) = stream.write_all(text.as_bytes()) {
        if error.kind() == ErrorKind::BrokenPipe {
            // This is fine, somebody probably just quit their pager before it
            // was done reading our output.
            exit(0);
        }

        panic!("Error writing diff to pager: {:?}", error);
    }
}

/**
A StringFuture can perform diffing in a background thread.

Doing get() on a future that isn't done yet will block until the result is
available.
*/
struct StringFuture {
    // This field is only valid if we're done with the result_receiver (next
    // field)
    result: String,

    // If available, get() will await a result on this receiver, then populate
    // the result field and return it
    result_receiver: Option<Receiver<String>>,
}

impl StringFuture {
    /// Create an already-finished future
    pub fn from_string(result: String) -> StringFuture {
        return StringFuture {
            result,
            result_receiver: None,
        };
    }

    /// Call get() to get the result of this diff
    pub fn from_oldnew(
        old_text: String,
        new_text: String,
        thread_pool: &ThreadPool,
    ) -> StringFuture {
        // Create a String channel
        let (sender, receiver): (SyncSender<String>, Receiver<String>) = sync_channel(1);

        // Start diffing in a thread
        thread_pool.execute(move || {
            let mut result = String::new();
            for line in refiner::format(&old_text, &new_text) {
                result.push_str(&line);
                result.push('\n');
            }

            // Done, channel the result!
            sender.send(result).unwrap();
        });

        return StringFuture {
            result: "".to_string(),
            result_receiver: Some(receiver),
        };
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn is_empty(&mut self) -> bool {
        return self.get().is_empty();
    }

    pub fn get(&mut self) -> &str {
        // If the result is still pending...
        if let Some(receiver) = &self.result_receiver {
            // ... wait for it
            self.result = receiver.recv().unwrap();
            self.result_receiver = None;
        }

        return &self.result;
    }
}

/**
The way this thing works from the outside is that you initialize it with an
output stream, you pass it one line of input at a time, and it writes
formatted lines to the output stream.

From the inside, it will collect blocks of either diff lines or not-diff-lines.

The not-diff-lines blocks will be enqueued for printing by the printing thread.

The diff lines blocks will also be enqueued for printing, but the actual diffing
will happen in background threads.
*/
pub struct LineCollector {
    old_text: String,
    new_text: String,
    plain_text: String,
    consumer_thread: Option<JoinHandle<()>>,

    diffing_threads: ThreadPool,

    // FIXME: I'd rather have had a SyncSender of some trait here. That would
    // enable us to have two separate result implementations, one which just
    // returns a string and another that does a background computation first.
    // But I failed to figure out how when I tried, more Googling needed!
    queue_putter: SyncSender<StringFuture>,
}

impl Drop for LineCollector {
    fn drop(&mut self) {
        // Flush any outstanding lines. This can be done in any order, at most
        // one of them is going to do anything anyway.
        self.drain_oldnew();
        self.drain_plain();

        // Tell the consumer thread to drain and quit. Sending an empty string
        // like this is the secret handshake for requesting a shutdown.
        self.queue_putter
            .send(StringFuture::from_string("".to_string()))
            .unwrap();

        // Wait for the consumer thread to finish
        // https://stackoverflow.com/q/57670145/473672
        self.consumer_thread.take().map(JoinHandle::join);
    }
}

impl LineCollector {
    pub fn new<W: io::Write + Send + 'static>(output: W) -> LineCollector {
        // This is how many entries we can look ahead. An "entry" in this case
        // being either a plain text section or an oldnew section.
        //
        // Benchmark timings with different multipliers on an 8 logical cores
        // machine with a 6.6M lines / 208MB diff:
        //
        // 500x => 5.68s  <-- Not much better than 100x
        // 100x => 5.71s  <-- Somewhat better than 50x
        //  50x => 5.98s
        //  10x >= 7.41s  <-- Much worse than 50x
        let queue_size = num_cpus::get() * 100;

        // Allocate a queue where we can push our futures to the consumer thread
        let (queue_putter, queue_getter): (SyncSender<StringFuture>, Receiver<StringFuture>) =
            sync_channel(queue_size);

        // This thread takes futures and prints their results
        let thread_builder = thread::Builder::new().name("Output Printer Thread".to_string());
        let consumer = thread_builder
            .spawn(move || {
                let mut output = BufWriter::new(output);

                loop {
                    if let Ok(mut print_me) = queue_getter.recv() {
                        if print_me.is_empty() {
                            // Secret handshake received, done!
                            break;
                        }
                        print(&mut output, print_me.get());
                    }
                }
            })
            .unwrap();

        return LineCollector {
            old_text: String::from(""),
            new_text: String::from(""),
            plain_text: String::from(""),
            consumer_thread: Some(consumer),
            diffing_threads: ThreadPool::new(num_cpus::get()),
            queue_putter,
        };
    }

    fn drain_oldnew(&mut self) {
        if self.old_text.is_empty() && self.new_text.is_empty() {
            return;
        }

        self.queue_putter
            .send(StringFuture::from_oldnew(
                self.old_text.clone(),
                self.new_text.clone(),
                &self.diffing_threads,
            ))
            .unwrap();

        self.old_text.clear();
        self.new_text.clear();
    }

    fn drain_plain(&mut self) {
        if self.plain_text.is_empty() {
            return;
        }

        // Enqueue an already-resolved future
        self.queue_putter
            .send(StringFuture::from_string(String::from(&self.plain_text)))
            .unwrap();

        self.plain_text.clear();
    }

    fn consume_plain_line(&mut self, line: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(line);
        self.plain_text.push('\n');
    }

    /// Like consume_plain_line(), but without outputting any trailing linefeed.
    fn consume_plain_linepart(&mut self, linepart: &str) {
        self.drain_oldnew();
        self.plain_text.push_str(linepart);
    }

    fn consume_old_line(&mut self, line: &str) {
        self.drain_plain();
        self.old_text.push_str(&line[1..]);
        self.old_text.push('\n');
    }

    fn consume_new_line(&mut self, line: &str) {
        self.drain_plain();
        self.new_text.push_str(&line[1..]);
        self.new_text.push('\n');
    }

    fn consume_no_eof_newline_marker(&mut self) {
        if !self.new_text.is_empty() {
            // New section comes after old, so if we get in here it's a new
            // section that doesn't end in a newline. Remove its trailing
            // newline.
            assert!(self.new_text.pop().unwrap() == '\n');
            return;
        }

        if !self.old_text.is_empty() {
            // Old text doesn't end in a newline, remove its trailing newline
            assert!(self.old_text.pop().unwrap() == '\n');
            return;
        }

        // It's a piece of unchanged text that doesn't end in a newline, just
        // consume the colorized marker as plain text
        self.consume_plain_line(&format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, &NO_EOF_NEWLINE_MARKER, NORMAL
        ))
    }

    pub fn consume_plusminus_header(&mut self, line: &str) {
        self.consume_plain_linepart(BOLD);

        if let Some(last_tab_index) = line.rfind('\t') {
            self.consume_plain_linepart(&line[..last_tab_index]);

            // When I ran plain "diff" (no git involved), this trailing part
            // contained very precise file timestamps. I don't think those
            // provide much value, so let's faint them out.
            self.consume_plain_linepart(FAINT);
            self.consume_plain_linepart(&line[last_tab_index..]);
        } else {
            self.consume_plain_linepart(line);
        }

        self.consume_plain_line(NORMAL);
    }

    fn consume_hunk_header(&mut self, line: &str) {
        self.consume_plain_linepart(HUNK_HEADER);

        if let Some(second_atat_index) = line.find(" @@ ") {
            // Highlight the function name
            self.consume_plain_linepart(FAINT);
            self.consume_plain_linepart(&line[..(second_atat_index + 4)]);
            self.consume_plain_linepart(BOLD);
            self.consume_plain_linepart(&line[(second_atat_index + 4)..]);
        } else {
            self.consume_plain_linepart(line);
        }

        self.consume_plain_line(NORMAL);
    }

    pub fn consume_line(&mut self, line: String) {
        // Strip out incoming ANSI formatting. This enables us to highlight
        // already-colored input.
        let line = ANSI_COLOR_REGEX.replace_all(&line, "");

        if let Some(fixed_highlight) = get_fixed_highlight(&line) {
            self.consume_plain_linepart(fixed_highlight);
            self.consume_plain_linepart(&line);
            self.consume_plain_line(NORMAL); // consume_plain_line() will add a linefeed to the output
            return;
        }

        if line.starts_with("---") || line.starts_with("+++") {
            self.consume_plusminus_header(&line);
            return;
        }

        if line.starts_with("@@ ") {
            self.consume_hunk_header(&line);
            return;
        }

        if line.is_empty() {
            self.consume_plain_line("");
            return;
        }

        if line.starts_with('-') {
            self.consume_old_line(&line);
            return;
        }

        if line.starts_with('+') {
            self.consume_new_line(&line);
            return;
        }

        if line == NO_EOF_NEWLINE_MARKER {
            self.consume_no_eof_newline_marker();
            return;
        }

        self.consume_plain_line(&line);
    }
}
<|endoftext|>


<commit_before>#![feature(old_path)]

extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Sprite".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut scene = Scene::new();
    let tex = Path::new("./rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    let id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(id.clone(), &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(id.clone(), &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::{ PressEvent, RenderEvent };

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(id.clone(), &seq);
            scene.toggle(id.clone(), &rotate);
        }
    }
}
<commit_msg>Fix old_path import in sprite example<commit_after>#![feature(old_path)]

extern crate piston;
extern crate ai_behavior;
extern crate sprite;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;

use std::old_path::*;

use std::cell::RefCell;
use std::rc::Rc;

use sprite::*;
use ai_behavior::{
    Action,
    Sequence,
    Wait,
    WaitForever,
    While,
};

use sdl2_window::Sdl2Window;
use opengl_graphics::{
    GlGraphics,
    OpenGL,
    Texture,
};

fn main() {
    let (width, height) = (300, 300);
    let opengl = OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        piston::window::WindowSettings {
            title: "Sprite".to_string(),
            size: [width, height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut scene = Scene::new();
    let tex = Path::new("./rust-logo.png");
    let tex = Rc::new(Texture::from_path(&tex).unwrap());
    let mut sprite = Sprite::from_texture(tex.clone());
    sprite.set_position(width as f64 / 2.0, height as f64 / 2.0);

    let id = scene.add_child(sprite);

    // Run a sequence or animations.
    let seq = Sequence(vec![
        Action(Ease(EaseFunction::CubicOut, Box::new(ScaleTo(2.0, 0.5, 0.5)))),
        Action(Ease(EaseFunction::BounceOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Ease(EaseFunction::ElasticOut, Box::new(MoveBy(2.0, 0.0, -100.0)))),
        Action(Ease(EaseFunction::BackInOut, Box::new(MoveBy(1.0, 0.0, -100.0)))),
        Wait(0.5),
        Action(Ease(EaseFunction::ExponentialInOut, Box::new(MoveBy(1.0, 0.0, 100.0)))),
        Action(Blink(1.0, 5)),
        While(Box::new(WaitForever), vec![
            Action(Ease(EaseFunction::QuadraticIn, Box::new(FadeOut(1.0)))),
            Action(Ease(EaseFunction::QuadraticOut, Box::new(FadeIn(1.0)))),
        ]),
    ]);
    scene.run(id.clone(), &seq);

    // This animation and the one above can run in parallel.
    let rotate = Action(Ease(EaseFunction::ExponentialInOut,
        Box::new(RotateTo(2.0, 360.0))));
    scene.run(id.clone(), &rotate);

    println!("Press any key to pause/resume the animation!");

    let ref mut gl = GlGraphics::new(opengl);
    let window = RefCell::new(window);
    for e in piston::events(&window) {
        use piston::event::*;

        scene.event(&e);

        if let Some(args) = e.render_args() {
            use graphics::*;
            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
                graphics::clear([1.0, 1.0, 1.0, 1.0], gl);
                scene.draw(c.transform, gl);
            });
        }
        if let Some(_) = e.press_args() {
            scene.toggle(id.clone(), &seq);
            scene.toggle(id.clone(), &rotate);
        }
    }
}
<|endoftext|>


<commit_before>//! these are also doc comments
//! but for crates, modules or functions
//! triple quotes looks nicer than these sad

/// these are doc comments
/// boring kind of things to do here
/// ok has support for markdown inside
fn main() {

    // these are comments

    let x = 5;

    // no bloody paren nice
    if x == 5 {
        println!("yes x is 5");
    }
}
<commit_msg>completed if, moving into loops<commit_after>//! these are also doc comments
//! but for crates, modules or functions
//! triple quotes looks nicer than these sad

/// these are doc comments
/// boring kind of things to do here
/// ok has support for markdown inside
fn main() {

    // these are comments

    let x = 5;

    // no bloody paren nice
    if x == 5 {
        println!("yes x is 5");
    } else if x == 6 {
        println!("me too");
    } else {
        println!("never see me");
    }

    // another thing with let if
    // so if is an expression, right!
    let y = if x == 5 { x + 1 } else { x - 1 };

    println!("and y is: {}", y);
}
<|endoftext|>


<commit_before>use std::{error::Error, thread, time::Duration};

// Logging
use log::{error, info, LevelFilter};
use simple_logger::SimpleLogger;

// Network related
use dns_lookup;
use http::{header, Method, HeaderMap, HeaderValue};
use reqwest::blocking::{Client, Response};
use url::Url;

// Other stuff
use humantime;
use structopt::StructOpt;
use uptime_lib;

// The main config
#[derive(Debug, StructOpt)]
#[structopt(about = "Service for sending requests to the watchcat backend.")]
struct Config {
    /// Url where to send requests
    #[structopt(short, parse(try_from_str = Url::parse), long, env)]
    url: Url,

    /// HTTP method to use
    #[structopt(long, default_value = "POST", env)]
    method: String,

    /// Secret key to use
    #[structopt(long, env, hide_env_values = true)]
    key: Option<String>,

    /// Repeat request after interval, with units 'ms', 's', 'm', 'h', e.g. 2m30s
    #[structopt(long, parse(try_from_str = humantime::parse_duration), env)]
    repeat: Option<Duration>,

    /// Timeout for http request in seconds
    #[structopt(long, env)]
    timeout: Option<u16>,

    /// Check dns every x seconds before first request, for faster inital signal in case of long allowed timeout
    #[structopt(long, env)]
    checkdns: Option<u16>,

    /// Do not send uptime in heartbeat requests
    #[structopt(long, env)]
    nouptime: bool,

    /// Verbose mode
    #[structopt(short, long)]
    verbose: bool,
}

fn main() {
    let cfg = Config::from_args(); // Parse arguments

    // Initialize logger
    SimpleLogger::new().init().unwrap();
    if cfg.verbose {
        log::set_max_level(LevelFilter::Info);
    } else {
        log::set_max_level(LevelFilter::Warn);
    }

    info!("{:?}", &cfg);

    // Create HTTP client
    let mut client_builder = Client::builder();
    let mut headers = HeaderMap::new();

    // Add timeout if specified
    if let Some(http_timeout) = cfg.timeout {
        client_builder = client_builder.timeout(Duration::from_secs(http_timeout.into()));
    }

    // Add the secret key as authorization header
    if let Some(key) = &cfg.key {
        headers.insert(header::AUTHORIZATION, HeaderValue::from_str(&key).unwrap());
    }

    headers.insert(header::CONTENT_LENGTH, HeaderValue::from_static("0"));
    client_builder = client_builder.default_headers(headers);
    let client = client_builder.build().unwrap();

    // Preform DNS pre check loop if configured
    if let Some(check_dns_interval) = cfg.checkdns {
        if check_dns_interval > 0 {
            check_dns(check_dns_interval, cfg.url.domain().unwrap());
        }
    }

    loop {
        // Send the HTTP request
        match send_request(&client, &cfg) {
            Ok(resp) => {
                info!("Response {}: \"{}\"", resp.status().as_u16(), resp.text().unwrap_or_default());
            }
            Err(err) => {
                error!("Error during request: {}", err);
            }
        }

        if let Some(repeat_interval) = cfg.repeat {
            thread::sleep(repeat_interval);
        } else {
            break;
        }
    }
}

/// Try to resolve the domains DNS entry in a loop until it is succesful.
fn check_dns(interval: u16, domain: &str) {
    info!("Checking DNS");

    loop {
        if let Ok(dns_entries) = dns_lookup::lookup_host(domain) {
            info!("DNS lookup successful: {} -> {}", domain, dns_entries[0]);
            break;
        } else {
            info!("DNS lookup failed, retrying in {} seconds", interval);
            thread::sleep(Duration::from_secs(interval.into()));
        }
    }
}

/// Send a HTTP request
fn send_request(client: &Client, cfg: &Config) -> Result<Response, Box<dyn Error>> {
    let mut request_builder = client.request(Method::from_bytes(cfg.method.as_bytes())?, cfg.url.as_str());

    // Add current uptime as query parameter
    if !cfg.nouptime {
        request_builder = request_builder.query(&[("uptime", uptime_lib::get()?.as_secs().to_string())]);
    }

    let request = request_builder.build()?;

    info!("Requesting {}: {}", cfg.method, request.url().as_str());
    Ok(client.execute(request)?)
}
<commit_msg>rustfmt<commit_after>use std::{error::Error, thread, time::Duration};

// Logging
use log::{error, info, LevelFilter};
use simple_logger::SimpleLogger;

// Network related
use dns_lookup;
use http::{header, HeaderMap, HeaderValue, Method};
use reqwest::blocking::{Client, Response};
use url::Url;

// Other stuff
use humantime;
use structopt::StructOpt;
use uptime_lib;

// The main config
#[derive(Debug, StructOpt)]
#[structopt(about = "Service for sending requests to the watchcat backend.")]
struct Config {
    /// Url where to send requests
    #[structopt(short, parse(try_from_str = Url::parse), long, env)]
    url: Url,

    /// HTTP method to use
    #[structopt(long, default_value = "POST", env)]
    method: String,

    /// Secret key to use
    #[structopt(long, env, hide_env_values = true)]
    key: Option<String>,

    /// Repeat request after interval, with units 'ms', 's', 'm', 'h', e.g. 2m30s
    #[structopt(long, parse(try_from_str = humantime::parse_duration), env)]
    repeat: Option<Duration>,

    /// Timeout for http request in seconds
    #[structopt(long, env)]
    timeout: Option<u16>,

    /// Check dns every x seconds before first request, for faster inital signal in case of long allowed timeout
    #[structopt(long, env)]
    checkdns: Option<u16>,

    /// Do not send uptime in heartbeat requests
    #[structopt(long, env)]
    nouptime: bool,

    /// Verbose mode
    #[structopt(short, long)]
    verbose: bool,
}

fn main() {
    let cfg = Config::from_args(); // Parse arguments

    // Initialize logger
    SimpleLogger::new().init().unwrap();
    if cfg.verbose {
        log::set_max_level(LevelFilter::Info);
    } else {
        log::set_max_level(LevelFilter::Warn);
    }

    info!("{:?}", &cfg);

    // Create HTTP client
    let mut client_builder = Client::builder();
    let mut headers = HeaderMap::new();

    // Add timeout if specified
    if let Some(http_timeout) = cfg.timeout {
        client_builder = client_builder.timeout(Duration::from_secs(http_timeout.into()));
    }

    // Add the secret key as authorization header
    if let Some(key) = &cfg.key {
        headers.insert(header::AUTHORIZATION, HeaderValue::from_str(&key).unwrap());
    }

    headers.insert(header::CONTENT_LENGTH, HeaderValue::from_static("0"));
    client_builder = client_builder.default_headers(headers);
    let client = client_builder.build().unwrap();

    // Preform DNS pre check loop if configured
    if let Some(check_dns_interval) = cfg.checkdns {
        if check_dns_interval > 0 {
            check_dns(check_dns_interval, cfg.url.domain().unwrap());
        }
    }

    loop {
        // Send the HTTP request
        match send_request(&client, &cfg) {
            Ok(resp) => {
                info!(
                    "Response {}: \"{}\"",
                    resp.status().as_u16(),
                    resp.text().unwrap_or_default()
                );
            }
            Err(err) => {
                error!("Error during request: {}", err);
            }
        }

        if let Some(repeat_interval) = cfg.repeat {
            thread::sleep(repeat_interval);
        } else {
            break;
        }
    }
}

/// Try to resolve the domains DNS entry in a loop until it is succesful.
fn check_dns(interval: u16, domain: &str) {
    info!("Checking DNS");

    loop {
        if let Ok(dns_entries) = dns_lookup::lookup_host(domain) {
            info!("DNS lookup successful: {} -> {}", domain, dns_entries[0]);
            break;
        } else {
            info!("DNS lookup failed, retrying in {} seconds", interval);
            thread::sleep(Duration::from_secs(interval.into()));
        }
    }
}

/// Send a HTTP request
fn send_request(client: &Client, cfg: &Config) -> Result<Response, Box<dyn Error>> {
    let mut request_builder =
        client.request(Method::from_bytes(cfg.method.as_bytes())?, cfg.url.as_str());

    // Add current uptime as query parameter
    if !cfg.nouptime {
        request_builder =
            request_builder.query(&[("uptime", uptime_lib::get()?.as_secs().to_string())]);
    }

    let request = request_builder.build()?;

    info!("Requesting {}: {}", cfg.method, request.url().as_str());
    Ok(client.execute(request)?)
}
<|endoftext|>


<commit_before>extern crate fitsio;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;
use fitsio::FitsFile;
use fitsio::fitsfile::ImageDescription;
use fitsio::types::ImageType;
use fitsio::columndescription::{ColumnDataType, ColumnDescription};

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::DOUBLE_IMG,
        dimensions: &[512, 1024],
    };

    {
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::LONG_IMG,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Get the primary HDU and read a section of the image data */

    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 100);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<commit_msg>Use pretty printing in full example<commit_after>extern crate fitsio;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;
use fitsio::FitsFile;
use fitsio::fitsfile::ImageDescription;
use fitsio::types::ImageType;
use fitsio::columndescription::{ColumnDataType, ColumnDescription};

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::DOUBLE_IMG,
        dimensions: &[512, 1024],
    };

    {
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::LONG_IMG,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Print the fits file contents to stdout */
    fitsfile.pretty_print().expect("printing fits file");

    /* Get the primary HDU and read a section of the image data */
    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 100);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<|endoftext|>


<commit_before>use crate::stream::{StreamExt, Fuse};
use core::pin::Pin;
use futures_core::stream::{FusedStream, Stream};
use futures_core::task::{Context, Poll};
#[cfg(feature = "sink")]
use futures_sink::Sink;
use pin_utils::{unsafe_pinned, unsafe_unpinned};

/// A `Stream` that implements a `peek` method.
///
/// The `peek` method can be used to retrieve a reference
/// to the next `Stream::Item` if available. A subsequent
/// call to `poll` will return the owned item.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Peekable<St: Stream> {
    stream: Fuse<St>,
    peeked: Option<St::Item>,
}

impl<St: Stream + Unpin> Unpin for Peekable<St> {}

impl<St: Stream> Peekable<St> {
    unsafe_pinned!(stream: Fuse<St>);
    unsafe_unpinned!(peeked: Option<St::Item>);

    pub(super) fn new(stream: St) -> Peekable<St> {
        Peekable {
            stream: stream.fuse(),
            peeked: None
        }
    }

    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    pub fn get_ref(&self) -> &St {
        self.stream.get_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_mut(&mut self) -> &mut St {
        self.stream.get_mut()
    }

    /// Acquires a pinned mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut St> {
        self.stream().get_pin_mut()
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    pub fn into_inner(self) -> St {
        self.stream.into_inner()
    }

    /// Peek retrieves a reference to the next item in the stream.
    ///
    /// This method polls the underlying stream and return either a reference
    /// to the next item if the stream is ready or passes through any errors.
    pub fn peek(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<&St::Item>> {
        if self.peeked.is_some() {
            let this: &Self = self.into_ref().get_ref();
            return Poll::Ready(this.peeked.as_ref())
        }
        match ready!(self.as_mut().stream().poll_next(cx)) {
            None => Poll::Ready(None),
            Some(item) => {
                *self.as_mut().peeked() = Some(item);
                let this: &Self = self.into_ref().get_ref();
                Poll::Ready(this.peeked.as_ref())
            }
        }
    }
}

impl<St: Stream> FusedStream for Peekable<St> {
    fn is_terminated(&self) -> bool {
        self.peeked.is_none() && self.stream.is_terminated()
    }
}

impl<S: Stream> Stream for Peekable<S> {
    type Item = S::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        if let Some(item) = self.as_mut().peeked().take() {
            return Poll::Ready(Some(item))
        }
        self.as_mut().stream().poll_next(cx)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = if self.peeked.is_some() { 1 } else { 0 };
        let (lower, upper) = self.stream.size_hint();
        let lower = lower.saturating_add(peek_len);
        let upper = match upper {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lower, upper)
    }
}

// Forwarding impl of Sink from the underlying stream
#[cfg(feature = "sink")]
impl<S, Item> Sink<Item> for Peekable<S>
    where S: Sink<Item> + Stream
{
    type Error = S::Error;

    delegate_sink!(stream, Item);
}
<commit_msg>Rename Peekable::peek to poll_peek<commit_after>use crate::stream::{StreamExt, Fuse};
use core::pin::Pin;
use futures_core::stream::{FusedStream, Stream};
use futures_core::task::{Context, Poll};
#[cfg(feature = "sink")]
use futures_sink::Sink;
use pin_utils::{unsafe_pinned, unsafe_unpinned};

/// A `Stream` that implements a `peek` method.
///
/// The `peek` method can be used to retrieve a reference
/// to the next `Stream::Item` if available. A subsequent
/// call to `poll` will return the owned item.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Peekable<St: Stream> {
    stream: Fuse<St>,
    peeked: Option<St::Item>,
}

impl<St: Stream + Unpin> Unpin for Peekable<St> {}

impl<St: Stream> Peekable<St> {
    unsafe_pinned!(stream: Fuse<St>);
    unsafe_unpinned!(peeked: Option<St::Item>);

    pub(super) fn new(stream: St) -> Peekable<St> {
        Peekable {
            stream: stream.fuse(),
            peeked: None
        }
    }

    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    pub fn get_ref(&self) -> &St {
        self.stream.get_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_mut(&mut self) -> &mut St {
        self.stream.get_mut()
    }

    /// Acquires a pinned mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut St> {
        self.stream().get_pin_mut()
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    pub fn into_inner(self) -> St {
        self.stream.into_inner()
    }

    /// Peek retrieves a reference to the next item in the stream.
    ///
    /// This method polls the underlying stream and return either a reference
    /// to the next item if the stream is ready or passes through any errors.
    pub fn poll_peek(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<&St::Item>> {
        if self.peeked.is_some() {
            let this: &Self = self.into_ref().get_ref();
            return Poll::Ready(this.peeked.as_ref())
        }
        match ready!(self.as_mut().stream().poll_next(cx)) {
            None => Poll::Ready(None),
            Some(item) => {
                *self.as_mut().peeked() = Some(item);
                let this: &Self = self.into_ref().get_ref();
                Poll::Ready(this.peeked.as_ref())
            }
        }
    }
}

impl<St: Stream> FusedStream for Peekable<St> {
    fn is_terminated(&self) -> bool {
        self.peeked.is_none() && self.stream.is_terminated()
    }
}

impl<S: Stream> Stream for Peekable<S> {
    type Item = S::Item;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        if let Some(item) = self.as_mut().peeked().take() {
            return Poll::Ready(Some(item))
        }
        self.as_mut().stream().poll_next(cx)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let peek_len = if self.peeked.is_some() { 1 } else { 0 };
        let (lower, upper) = self.stream.size_hint();
        let lower = lower.saturating_add(peek_len);
        let upper = match upper {
            Some(x) => x.checked_add(peek_len),
            None => None,
        };
        (lower, upper)
    }
}

// Forwarding impl of Sink from the underlying stream
#[cfg(feature = "sink")]
impl<S, Item> Sink<Item> for Peekable<S>
    where S: Sink<Item> + Stream
{
    type Error = S::Error;

    delegate_sink!(stream, Item);
}
<|endoftext|>