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

//! An interface for numeric types
use cmp::Eq;
use option::{None, Option, Some};

pub trait Num {
    // FIXME: Trait composition. (#2616)
    pure fn add(&self, other: &Self) -> Self;
    pure fn sub(&self, other: &Self) -> Self;
    pure fn mul(&self, other: &Self) -> Self;
    pure fn div(&self, other: &Self) -> Self;
    pure fn modulo(&self, other: &Self) -> Self;
    pure fn neg(&self) -> Self;

    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait IntConvertible {
    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait Zero {
    static pure fn zero() -> Self;
}

pub trait One {
    static pure fn one() -> Self;
}

pub trait Round {
    pure fn round(&self, mode: RoundMode) -> self;

    pure fn floor(&self) -> self;
    pure fn ceil(&self)  -> self;
    pure fn fract(&self) -> self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

pub trait ToStrRadix {
    pub pure fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    static pub pure fn from_str_radix(str: &str, radix: uint) -> Option<self>;
}

// Generic math functions:

/// Dynamically calculates the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    _1 / _0
}

/// Dynamically calculates the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn neg_infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    - _1 / _0
}

/// Dynamically calculates the value `NaN` (`0/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn NaN<T: Num Zero>() -> T {
    let _0: T = Zero::zero();
    _0 / _0
}

/// Returns `true` if `num` has the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (infinity::<T>())
}

/// Returns `true` if `num` has the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (neg_infinity::<T>())
}

/// Returns `true` if `num` has the value `NaN` (is not equal to itself).
#[inline(always)]
pub pure fn is_NaN<T: Num Eq>(num: &T) -> bool {
    (*num) != (*num)
}

/// Returns `true` if `num` has the value `-0` (`1/num == -1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_zero<T: Num One Zero Eq>(num: &T) -> bool {
    let _1: T = One::one();
    let _0: T = Zero::zero();
    *num == _0 && is_neg_infinity(&(_1 / *num))
}

/**
 * Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 *
 * Returns `radix^pow` as `T`.
 *
 * Note:
 * Also returns `1` for `0^0`, despite that technically being an
 * undefined number. The Reason for this is twofold:
 * - If code written to use this function cares about that special case, it's
 *   probably going to catch it before making the call.
 * - If code written to use this function doesn't care about it, it's
 *   probably assuming that `x^0` always equals `1`.
 */
pub pure fn pow_with_uint<T: Num One Zero>(radix: uint, pow: uint) -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();

    if pow   == 0u { return _1; }
    if radix == 0u { return _0; }
    let mut my_pow     = pow;
    let mut total      = _1;
    let mut multiplier = Num::from_int(radix as int);
    while (my_pow > 0u) {
        if my_pow % 2u == 1u {
            total *= multiplier;
        }
        my_pow     /= 2u;
        multiplier *= multiplier;
    }
    total
}<commit_msg>Added generic string <-> number conversion functions to core::num.<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.

//! An interface for numeric types
use core::cmp::{Ord, Eq};
use option::{None, Option, Some};
use char;
use str;
use kinds::Copy;
use vec;

pub trait Num {
    // FIXME: Trait composition. (#2616)
    pure fn add(&self, other: &Self) -> Self;
    pure fn sub(&self, other: &Self) -> Self;
    pure fn mul(&self, other: &Self) -> Self;
    pure fn div(&self, other: &Self) -> Self;
    pure fn modulo(&self, other: &Self) -> Self;
    pure fn neg(&self) -> Self;

    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait IntConvertible {
    pure fn to_int(&self) -> int;
    static pure fn from_int(n: int) -> Self;
}

pub trait Zero {
    static pure fn zero() -> Self;
}

pub trait One {
    static pure fn one() -> Self;
}

pub trait Round {
    pure fn round(&self, mode: RoundMode) -> self;

    pure fn floor(&self) -> self;
    pure fn ceil(&self)  -> self;
    pure fn fract(&self) -> self;
}

pub enum RoundMode {
    RoundDown,
    RoundUp,
    RoundToZero,
    RoundFromZero
}

pub trait ToStrRadix {
    pub pure fn to_str_radix(&self, radix: uint) -> ~str;
}

pub trait FromStrRadix {
    static pub pure fn from_str_radix(str: &str, radix: uint) -> Option<self>;
}

// Generic math functions:

/// Dynamically calculates the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    _1 / _0
}

/// Dynamically calculates the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn neg_infinity<T: Num One Zero>() -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();
    - _1 / _0
}

/// Dynamically calculates the value `NaN` (`0/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn NaN<T: Num Zero>() -> T {
    let _0: T = Zero::zero();
    _0 / _0
}

/// Returns `true` if `num` has the value `inf` (`1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (infinity::<T>())
}

/// Returns `true` if `num` has the value `-inf` (`-1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_infinity<T: Num One Zero Eq>(num: &T) -> bool {
    (*num) == (neg_infinity::<T>())
}

/// Returns `true` if `num` has the value `NaN` (is not equal to itself).
#[inline(always)]
pub pure fn is_NaN<T: Num Eq>(num: &T) -> bool {
    (*num) != (*num)
}

/// Returns `true` if `num` has the value `-0` (`1/num == -1/0`).
/// Can fail on integer types.
#[inline(always)]
pub pure fn is_neg_zero<T: Num One Zero Eq>(num: &T) -> bool {
    let _1: T = One::one();
    let _0: T = Zero::zero();
    *num == _0 && is_neg_infinity(&(_1 / *num))
}

/**
 * Calculates a power to a given radix, optimized for uint `pow` and `radix`.
 *
 * Returns `radix^pow` as `T`.
 *
 * Note:
 * Also returns `1` for `0^0`, despite that technically being an
 * undefined number. The reason for this is twofold:
 * - If code written to use this function cares about that special case, it's
 *   probably going to catch it before making the call.
 * - If code written to use this function doesn't care about it, it's
 *   probably assuming that `x^0` always equals `1`.
 */
pub pure fn pow_with_uint<T: Num One Zero>(radix: uint, pow: uint) -> T {
    let _0: T = Zero::zero();
    let _1: T = One::one();

    if pow   == 0u { return _1; }
    if radix == 0u { return _0; }
    let mut my_pow     = pow;
    let mut total      = _1;
    let mut multiplier = Num::from_int(radix as int);
    while (my_pow > 0u) {
        if my_pow % 2u == 1u {
            total *= multiplier;
        }
        my_pow     /= 2u;
        multiplier *= multiplier;
    }
    total
}

pub enum ExponentFormat {
    ExpNone,
    ExpDec,
    ExpBin
}

pub enum SignificantDigits {
    DigAll,
    DigMax(uint),
    DigExact(uint)
}

pub enum SignFormat {
    SignNone,
    SignNeg,
    SignAll
}

/**
 * Converts a number to its string representation as a byte vector.
 * This is meant to be a common base implementation for all numeric string
 * conversion functions like `to_str()` or `to_str_radix()`.
 *
 * # Arguments
 * - `num`           - The number to convert. Accepts any number that
 *                     implements the numeric traits.
 * - `radix`         - Base to use. Accepts only the values 2-36.
 * - `special`       - Whether to attempt to compare to special values like
 *                     `inf` or `NaN`. Also needed to detect negative 0.
 *                     Can fail if it doesn't match `num`s type
 *                     (see safety note).
 * - `negative_zero` - Whether to treat the special value `-0` as
 *                     `-0` or as `+0`.
 * - `sign`          - How to emit the sign. Options are:
 *     - `SignNone`: No sign at all. Basically emits `abs(num)`.
 *     - `SignNeg`:  Only `-` on negative values.
 *     - `SignAll`:  Both `+` on positive, and `-` on negative numbers.
 * - `digits`        - The amount of digits to use for emitting the
 *                     fractional part, if any. Options are:
 *     - `DigAll`:         All calculatable digits. Beware of bignums or
 *                         fractions!
 *     - `DigMax(uint)`:   Maximum N digits, truncating any trailing zeros.
 *     - `DigExact(uint)`: Exactly N digits.
 *
 * # Return value
 * A tuple containing the byte vector, and a boolean flag indicating
 * whether it represents a special value like `inf`, `-inf`, `NaN` or not.
 * It returns a tuple because there can be ambiguity between a special value
 * and a number representation at higher bases.
 *
 * # Failure
 * - Fails if `radix` < 2 or `radix` > 36.
 * - Fails on wrong value for `special` (see safety note).
 *
 * # Safety note
 * The function detects the special values `inf`, `-inf` and `NaN` by
 * dynamically comparing `num` to `1 / 0`, `-1 / 0` and `0 / 0`
 * (each of type T) if `special` is `true`. This will fail on integer types
 * with a 'divide by zero'. Likewise, it will fail if `num` **is** one of
 * those special values, and `special` is `false`, because then the
 * algorithm just does normal calculations on them.
 *
 * # Possible improvements
 * - Currently performs no rounding if truncating trailing digits.
 * - Make function handle numbers with expensive copies better.
 */
pub pure fn to_str_bytes_common<T: Num Zero One Eq Ord Round Copy>(
        num: &T, radix: uint, special: bool, negative_zero: bool,
        sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
    if radix as int <  2 {
        fail fmt!("to_str_bytes_common: radix %? to low, \
                   must lie in the range [2, 36]", radix);
    } else if radix as int > 36 {
        fail fmt!("to_str_bytes_common: radix %? to high, \
                   must lie in the range [2, 36]", radix);
    }

    let _0: T = Zero::zero();
    let _1: T = One::one();

    if special {
        if is_NaN(num) {
            return (str::to_bytes("NaN"), true);
        } else if is_infinity(num){
            return match sign {
                SignAll => (str::to_bytes("+inf"), true),
                _       => (str::to_bytes("inf"), true)
            }
        } else if is_neg_infinity(num) {
            return match sign {
                SignNone => (str::to_bytes("inf"), true),
                _        => (str::to_bytes("-inf"), true),
            }
        }
    }

    let neg = *num < _0 || (negative_zero && *num == _0
                            && special && is_neg_zero(num));
    let mut buf: ~[u8] = ~[];
    let radix_gen      = Num::from_int::<T>(radix as int);

    let mut deccum;

    // First emit the non-fractional part, looping at least once to make
    // sure at least a `0` gets emitted.
    deccum = num.round(RoundToZero);
    loop {
        // Calculate the absolute value of each digit instead of only
        // doing it once for the whole number because a
        // representable negative number doesn't necessary have an
        // representable additive inverse of the same type
        // (See twos complement). But we assume that for the
        // numbers [-35 .. 0] we always have [0 .. 35].
        let current_digit_signed = deccum % radix_gen;
        let current_digit = if current_digit_signed < _0 {
            -current_digit_signed
        } else {
            current_digit_signed
        };

        // Decrease the deccumulator one digit at a time
        deccum /= radix_gen;
        deccum = deccum.round(RoundToZero);

        unsafe { // FIXME: Pureness workaround (#4568)
            buf.push(char::from_digit(current_digit.to_int() as uint, radix)
                 .unwrap() as u8);
        }

        // No more digits to calculate for the non-fractional part -> break
        if deccum == _0 { break; }
    }

    // If limited digits, calculate one digit more for rounding.
    let (limit_digits, digit_count, exact) = match digits {
        DigAll          => (false, 0u,      false),
        DigMax(count)   => (true,  count+1, false),
        DigExact(count) => (true,  count+1, true)
    };

    // Decide what sign to put in front
    match sign {
        SignNeg | SignAll if neg => {
            unsafe { // FIXME: Pureness workaround (#4568)
                buf.push('-' as u8);
            }
        }
        SignAll => {
            unsafe { // FIXME: Pureness workaround (#4568)
                buf.push('+' as u8);
            }
        }
        _ => ()
    }

    unsafe { // FIXME: Pureness workaround (#4568)
        vec::reverse(buf);
    }

    // Remember start of the fractional digits.
    // Points one beyond end of buf if none get generated,
    // or at the '.' otherwise.
    let start_fractional_digits = buf.len();

    // Now emit the fractional part, if any
    deccum = num.fract();
    if deccum != _0 || (limit_digits && exact && digit_count > 0) {
        unsafe { // FIXME: Pureness workaround (#4568)
            buf.push('.' as u8);
        }
        let mut dig = 0u;

        // calculate new digits while
        // - there is no limit and there are digits left
        // - or there is a limit, it's not reached yet and
        //   - it's exact
        //   - or it's a maximum, and there are still digits left
        while (!limit_digits && deccum != _0)
           || (limit_digits && dig < digit_count && (
                   exact
                || (!exact && deccum != _0)
              )
        ) {
            // Shift first fractional digit into the integer part
            deccum *= radix_gen;

            // Calculate the absolute value of each digit.
            // See note in first loop.
            let current_digit_signed = deccum.round(RoundToZero);
            let current_digit = if current_digit_signed < _0 {
                -current_digit_signed
            } else {
                current_digit_signed
            };

            unsafe { // FIXME: Pureness workaround (#4568)
                buf.push(char::from_digit(
                    current_digit.to_int() as uint, radix).unwrap() as u8);
            }

            // Decrease the deccumulator one fractional digit at a time
            deccum = deccum.fract();
            dig += 1u;
        }

        // If digits are limited, and that limit has been reached,
        // cut off the one extra digit, and depending on its value
        // round the remaining ones.
        if limit_digits && dig == digit_count {
            let ascii2value = |chr: u8| {
                char::to_digit(chr as char, radix).unwrap() as uint
            };
            let value2ascii = |val: uint| {
                char::from_digit(val, radix).unwrap() as u8
            };

            unsafe { // FIXME: Pureness workaround (#4568)
                let extra_digit = ascii2value(buf.pop());
                if extra_digit >= radix / 2 { // -> need to round
                    let mut i: int = buf.len() as int - 1;
                    loop {
                        // If reached left end of number, have to
                        // insert additional digit:
                        if i < 0
                        || buf[i] == '-' as u8
                        || buf[i] == '+' as u8 {
                            buf.insert((i + 1) as uint, value2ascii(1));
                            break;
                        }

                        // Skip the '.'
                        if buf[i] == '.' as u8 { i -= 1; loop; }

                        // Either increment the digit,
                        // or set to 0 if max and carry the 1.
                        let current_digit = ascii2value(buf[i]);
                        if current_digit < (radix - 1) {
                            buf[i] = value2ascii(current_digit+1);
                            break;
                        } else {
                            buf[i] = value2ascii(0);
                            i -= 1;
                        }
                    }
                }
            }
        }
    }

    // if number of digits is not exact, remove all trailing '0's up to
    // and including the '.'
    if !exact {
        let buf_max_i = buf.len() - 1;

        // index to truncate from
        let mut i = buf_max_i;

        // discover trailing zeros of fractional part
        while i > start_fractional_digits && buf[i] == '0' as u8 {
            i -= 1;
        }

        // Only attempt to truncate digits if buf has fractional digits
        if i >= start_fractional_digits {
            // If buf ends with '.', cut that too.
            if buf[i] == '.' as u8 { i -= 1 }

            // only resize buf if we actually remove digits
            if i < buf_max_i {
                buf = buf.slice(0, i + 1);
            }
        }
    }

    (buf, false)
}

/**
 * Converts a number to its string representation. This is a wrapper for
 * `to_str_bytes_common()`, for details see there.
 */
#[inline(always)]
pub pure fn to_str_common<T: Num Zero One Eq Ord Round Copy>(
        num: &T, radix: uint, special: bool, negative_zero: bool,
        sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
    let (bytes, special) = to_str_bytes_common(num, radix, special,
                               negative_zero, sign, digits);
    (str::from_bytes(bytes), special)
}

// Some constants for from_str_bytes_common's input validation,
// they define minimum radix values for which the character is a valid digit.
priv const DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
priv const DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
priv const DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;

/**
 * Parses a byte slice as a number. This is meant to
 * be a common base implementation for all numeric string conversion
 * functions like `from_str()` or `from_str_radix()`.
 *
 * # Arguments
 * - `buf`        - The byte slice to parse.
 * - `radix`      - Which base to parse the number as. Accepts 2-36.
 * - `negative`   - Whether to accept negative numbers.
 * - `fractional` - Whether to accept numbers with fractional parts.
 * - `special`    - Whether to accept special values like `inf`
 *                  and `NaN`. Can conflict with `radix`, see Failure.
 * - `exponent`   - Which exponent format to accept. Options are:
 *     - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
 *                  `-8.2`.
 *     - `ExpDec`:  Accepts numbers with a decimal exponent like `42e5` or
 *                  `8.2E-2`. The exponent string itself is always base 10.
 *                  Can conflict with `radix`, see Failure.
 *     - `ExpBin`:  Accepts numbers with a binary exponent like `42P-8` or
 *                  `FFp128`. The exponent string itself is always base 10.
 *                  Can conflict with `radix`, see Failure.
 * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not.
 *
 * # Return value
 * Returns `Some(n)` if `buf` parses to a number n without overflowing, and
 * `None` otherwise, depending on the constraints set by the remaining
 * arguments.
 *
 * # Failure
 * - Fails if `radix` < 2 or `radix` > 36.
 * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict
 *   between digit and exponent sign `'e'`.
 * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict
 *   between digit and exponent sign `'p'`.
 * - Fails if `radix` > 18 and `special == true` due to conflict
 *   between digit and lowest first character in `inf` and `NaN`, the `'i'`.
 *
 * # Possible improvements
 * - Could accept option to allow ignoring underscores, allowing for numbers
 *   formated like `FF_AE_FF_FF`.
 */
pub pure fn from_str_bytes_common<T: Num Zero One Ord Copy>(
        buf: &[u8], radix: uint, negative: bool, fractional: bool,
        special: bool, exponent: ExponentFormat, empty_zero: bool
        ) -> Option<T> {
    match exponent {
        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
          => fail fmt!("from_str_bytes_common: radix %? incompatible with \
                        use of 'e' as decimal exponent", radix),
        ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
          => fail fmt!("from_str_bytes_common: radix %? incompatible with \
                        use of 'p' as binary exponent", radix),
        _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf'
          => fail fmt!("from_str_bytes_common: radix %? incompatible with \
                        special values 'inf' and 'NaN'", radix),
        _ if radix as int < 2
          => fail fmt!("from_str_bytes_common: radix %? to low, \
                        must lie in the range [2, 36]", radix),
        _ if radix as int > 36
          => fail fmt!("from_str_bytes_common: radix %? to high, \
                        must lie in the range [2, 36]", radix),
        _ => ()
    }

    let _0: T = Zero::zero();
    let _1: T = One::one();
    let radix_gen: T = Num::from_int(radix as int);

    let len = buf.len();

    if len == 0 {
        if empty_zero {
            return Some(_0);
        } else {
            return None;
        }
    }

    if special {
        if buf == str::to_bytes("inf") || buf == str::to_bytes("+inf") {
            return Some(infinity());
        } else if buf == str::to_bytes("-inf") {
            if negative {
                return Some(neg_infinity());
            } else {
                return None;
            }
        } else if buf == str::to_bytes("NaN") {
            return Some(NaN());
        }
    }

    let (start, accum_positive) = match buf[0] {
      '-' as u8 if !negative => return None,
      '-' as u8 => (1u, false),
      '+' as u8 => (1u, true),
       _        => (0u, true)
    };

    // Initialize accumulator with signed zero for floating point parsing to
    // work
    let mut accum      = if accum_positive { _0 } else { -_1 * _0};
    let mut last_accum = accum; // Necessary to detect overflow
    let mut i          = start;
    let mut exp_found  = false;

    // Parse integer part of number
    while i < len {
        let c = buf[i] as char;

        match char::to_digit(c, radix) {
            Some(digit) => {
                // shift accum one digit left
                accum *= radix_gen;

                // add/subtract current digit depending on sign
                if accum_positive {
                    accum += Num::from_int(digit as int);
                } else {
                    accum -= Num::from_int(digit as int);
                }

                // Detect overflow by comparing to last value
                if accum_positive && accum < last_accum { return None; }
                if !accum_positive && accum > last_accum { return None; }
                last_accum = accum;
            }
            None => match c {
                'e' | 'E' | 'p' | 'P' => {
                    exp_found = true;
                    break;                       // start of exponent
                }
                '.' if fractional => {
                    i += 1u;                     // skip the '.'
                    break;                       // start of fractional part
                }
                _ => return None                 // invalid number
            }
        }

        i += 1u;
    }

    // Parse fractional part of number
    // Skip if already reached start of exponent
    if !exp_found {
        let mut power = _1;

        while i < len {
            let c = buf[i] as char;

            match char::to_digit(c, radix) {
                Some(digit) => {
                    // Decrease power one order of magnitude
                    power /= radix_gen;

                    // add/subtract current digit depending on sign
                    if accum_positive {
                        accum += Num::from_int::<T>(digit as int) * power;
                    } else {
                        accum -= Num::from_int::<T>(digit as int) * power;
                    }

                    // Detect overflow by comparing to last value
                    if accum_positive && accum < last_accum { return None; }
                    if !accum_positive && accum > last_accum { return None; }
                    last_accum = accum;
                }
                None => match c {
                    'e' | 'E' | 'p' | 'P' => {
                        exp_found = true;
                        break;                   // start of exponent
                    }
                    _ => return None             // invalid number
                }
            }

            i += 1u;
        }
    }

    // Special case: buf not empty, but does not contain any digit in front
    // of the exponent sign -> number is empty string
    if i == start {
        if empty_zero {
            return Some(_0);
        } else {
            return None;
        }
    }

    let mut multiplier = _1;

    if exp_found {
        let c = buf[i] as char;
        let base = match (c, exponent) {
            ('e', ExpDec) | ('E', ExpDec) => 10u,
            ('p', ExpBin) | ('P', ExpBin) => 2u,
            _ => return None // char doesn't fit given exponent format
        };

        // parse remaining bytes as decimal integer,
        // skipping the exponent char
        let exp: Option<int> = from_str_bytes_common(
            buf.view(i+1, len), 10, true, false, false, ExpNone, false);

        match exp {
            Some(exp_pow) => {
                multiplier = if exp_pow < 0 {
                    _1 / pow_with_uint::<T>(base, (-exp_pow.to_int()) as uint)
                } else {
                    pow_with_uint::<T>(base, exp_pow.to_int() as uint)
                }
            }
            None => return None // invalid exponent -> invalid number
        }
    }

    Some(accum * multiplier)
}

/**
 * Parses a string as a number. This is a wrapper for
 * `from_str_bytes_common()`, for details see there.
 */
#[inline(always)]
pub pure fn from_str_common<T: Num Zero One Ord Copy>(
        buf: &str, radix: uint, negative: bool, fractional: bool,
        special: bool, exponent: ExponentFormat, empty_zero: bool
        ) -> Option<T> {
    from_str_bytes_common(str::to_bytes(buf), radix, negative,
                            fractional, special, exponent, empty_zero)
}<|endoftext|>


<commit_before>// Copyright 2014 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 core prelude
//!
//! For more information, see std::prelude.

// Reexported core operators
pub use kinds::{Copy, 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 iter::range;
pub use mem::drop;

// Reexported types and traits

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, Float};
pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
pub use ptr::RawPtr;
pub use str::{Str, StrSlice};
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};
pub use slice::{MutableVector};
pub use slice::{Vector, ImmutableVector};
<commit_msg>core: Clarify the documentation on core's prelude<commit_after>// Copyright 2014 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 core prelude
//!
//! This module is intended for users of libcore which do not link to libstd as
//! well. This module is not imported by default, but using the entire contents
//! of this module will provide all of the useful traits and types in libcore
//! that one would expect from the standard library as well.
//!
//! There is no method to automatically inject this prelude, and this prelude is
//! a subset of the standard library's prelude.
//!
//! # Example
//!
//! ```ignore
//! # fn main() {
//! #![feature(globs)]
//!
//! use core::prelude::*;
//! # }
//! ```

// Reexported core operators
pub use kinds::{Copy, 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 iter::range;
pub use mem::drop;

// Reexported types and traits

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, Float};
pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
pub use ptr::RawPtr;
pub use str::{Str, StrSlice};
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};
pub use slice::{MutableVector};
pub use slice::{Vector, ImmutableVector};
<|endoftext|>


<commit_before>//! The main parser interface

#[legacy_exports];

export parser;
export common;
export lexer;
export token;
export comments;
export prec;
export classify;
export attr;

export parse_sess;
export new_parse_sess, new_parse_sess_special_handler;
export next_node_id;
export new_parser_from_file, new_parser_etc_from_file;
export new_parser_from_source_str;
export new_parser_from_tts;
export new_sub_parser_from_file;
export parse_crate_from_file, parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str, parse_item_from_source_str;
export parse_stmt_from_source_str;
export parse_tts_from_source_str;
export parse_from_source_str;

use parser::Parser;
use attr::parser_attr;
use common::parser_common;
use ast::node_id;
use util::interner;
use diagnostic::{span_handler, mk_span_handler, mk_handler, emitter};
use lexer::{reader, string_reader};
use parse::token::{ident_interner, mk_ident_interner};
use codemap::{span, CodeMap, FileMap, CharPos, BytePos};

type parse_sess = @{
    cm: @codemap::CodeMap,
    mut next_id: node_id,
    span_diagnostic: span_handler,
    interner: @ident_interner,
};

fn new_parse_sess(demitter: Option<emitter>) -> parse_sess {
    let cm = @CodeMap::new();
    return @{cm: cm,
             mut next_id: 1,
             span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
             interner: mk_ident_interner(),
            };
}

fn new_parse_sess_special_handler(sh: span_handler, cm: @codemap::CodeMap)
    -> parse_sess {
    return @{cm: cm,
             mut next_id: 1,
             span_diagnostic: sh,
             interner: mk_ident_interner(),
             };
}

fn parse_crate_from_file(input: &Path, cfg: ast::crate_cfg,
                         sess: parse_sess) -> @ast::crate {
    let p = new_crate_parser_from_file(sess, cfg, input);
    let r = p.parse_crate_mod(cfg);
    return r;
}

fn parse_crate_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_crate_mod(cfg);
    p.abort_if_errors();
    return r;
}

fn parse_expr_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_expr();
    p.abort_if_errors();
    return r;
}

fn parse_item_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              +attrs: ~[ast::attribute],
                              sess: parse_sess) -> Option<@ast::item> {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_item(attrs);
    p.abort_if_errors();
    return r;
}

fn parse_stmt_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              +attrs: ~[ast::attribute],
                              sess: parse_sess) -> @ast::stmt {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_stmt(attrs);
    p.abort_if_errors();
    return r;
}

fn parse_tts_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                             sess: parse_sess) -> ~[ast::token_tree] {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    p.quote_depth += 1u;
    let r = p.parse_all_token_trees();
    p.abort_if_errors();
    return r;
}

fn parse_from_source_str<T>(f: fn (p: Parser) -> T,
                            name: ~str, ss: codemap::FileSubstr,
                            source: @~str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss,
                                       source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal(~"expected end-of-string");
    }
    p.abort_if_errors();
    move r
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    return rv;
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              +name: ~str, +ss: codemap::FileSubstr,
                              source: @~str) -> Parser {
    let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
    let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
                                        sess.interner);
    return Parser(sess, cfg, srdr as reader);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                        path: &Path) -> Result<Parser, ~str> {
    match io::read_whole_file_str(path) {
      result::Ok(move src) => {

          // HACK: If the file contains a special token use a different
          // source file. Used to send the stage1+ parser (the stage0 parser
          // doesn't have this hack) to a different crate file.
          // Transitional. Remove me.
          let src = if src.starts_with("// DIVERT") {
              let actual_path = &path.with_filestem("alternate_crate");
              result::unwrap(io::read_whole_file_str(actual_path))
          } else {
              move src
          };

          let filemap = sess.cm.new_filemap(path.to_str(), @move src);
          let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
                                              sess.interner);

          Ok(Parser(sess, cfg, srdr as reader))

      }
      result::Err(move e) => Err(move e)
    }
}

/// Create a new parser for an entire crate, handling errors as appropriate
/// if the file doesn't exist
fn new_crate_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                              path: &Path) -> Parser {
    match new_parser_from_file(sess, cfg, path) {
        Ok(move parser) => move parser,
        Err(move e) => {
            sess.span_diagnostic.handler().fatal(e)
        }
    }
}

/// Create a new parser based on a span from an existing parser. Handles
/// error messages correctly when the file does not exist.
fn new_sub_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                            path: &Path, sp: span) -> Parser {
    match new_parser_from_file(sess, cfg, path) {
        Ok(move parser) => move parser,
        Err(move e) => {
            sess.span_diagnostic.span_fatal(sp, e)
        }
    }
}

fn new_parser_from_tts(sess: parse_sess, cfg: ast::crate_cfg,
                       tts: ~[ast::token_tree]) -> Parser {
    let trdr = lexer::new_tt_reader(sess.span_diagnostic, sess.interner,
                                    None, tts);
    return Parser(sess, cfg, trdr as reader)
}
<commit_msg>Remove parser hack<commit_after>//! The main parser interface

#[legacy_exports];

export parser;
export common;
export lexer;
export token;
export comments;
export prec;
export classify;
export attr;

export parse_sess;
export new_parse_sess, new_parse_sess_special_handler;
export next_node_id;
export new_parser_from_file, new_parser_etc_from_file;
export new_parser_from_source_str;
export new_parser_from_tts;
export new_sub_parser_from_file;
export parse_crate_from_file, parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str, parse_item_from_source_str;
export parse_stmt_from_source_str;
export parse_tts_from_source_str;
export parse_from_source_str;

use parser::Parser;
use attr::parser_attr;
use common::parser_common;
use ast::node_id;
use util::interner;
use diagnostic::{span_handler, mk_span_handler, mk_handler, emitter};
use lexer::{reader, string_reader};
use parse::token::{ident_interner, mk_ident_interner};
use codemap::{span, CodeMap, FileMap, CharPos, BytePos};

type parse_sess = @{
    cm: @codemap::CodeMap,
    mut next_id: node_id,
    span_diagnostic: span_handler,
    interner: @ident_interner,
};

fn new_parse_sess(demitter: Option<emitter>) -> parse_sess {
    let cm = @CodeMap::new();
    return @{cm: cm,
             mut next_id: 1,
             span_diagnostic: mk_span_handler(mk_handler(demitter), cm),
             interner: mk_ident_interner(),
            };
}

fn new_parse_sess_special_handler(sh: span_handler, cm: @codemap::CodeMap)
    -> parse_sess {
    return @{cm: cm,
             mut next_id: 1,
             span_diagnostic: sh,
             interner: mk_ident_interner(),
             };
}

fn parse_crate_from_file(input: &Path, cfg: ast::crate_cfg,
                         sess: parse_sess) -> @ast::crate {
    let p = new_crate_parser_from_file(sess, cfg, input);
    let r = p.parse_crate_mod(cfg);
    return r;
}

fn parse_crate_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_crate_mod(cfg);
    p.abort_if_errors();
    return r;
}

fn parse_expr_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_expr();
    p.abort_if_errors();
    return r;
}

fn parse_item_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              +attrs: ~[ast::attribute],
                              sess: parse_sess) -> Option<@ast::item> {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_item(attrs);
    p.abort_if_errors();
    return r;
}

fn parse_stmt_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                              +attrs: ~[ast::attribute],
                              sess: parse_sess) -> @ast::stmt {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    let r = p.parse_stmt(attrs);
    p.abort_if_errors();
    return r;
}

fn parse_tts_from_source_str(name: ~str, source: @~str, cfg: ast::crate_cfg,
                             sess: parse_sess) -> ~[ast::token_tree] {
    let p = new_parser_from_source_str(sess, cfg, name,
                                       codemap::FssNone, source);
    p.quote_depth += 1u;
    let r = p.parse_all_token_trees();
    p.abort_if_errors();
    return r;
}

fn parse_from_source_str<T>(f: fn (p: Parser) -> T,
                            name: ~str, ss: codemap::FileSubstr,
                            source: @~str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss,
                                       source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal(~"expected end-of-string");
    }
    p.abort_if_errors();
    move r
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    return rv;
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              +name: ~str, +ss: codemap::FileSubstr,
                              source: @~str) -> Parser {
    let filemap = sess.cm.new_filemap_w_substr(name, ss, source);
    let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
                                        sess.interner);
    return Parser(sess, cfg, srdr as reader);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                        path: &Path) -> Result<Parser, ~str> {
    match io::read_whole_file_str(path) {
      result::Ok(move src) => {

          let filemap = sess.cm.new_filemap(path.to_str(), @move src);
          let srdr = lexer::new_string_reader(sess.span_diagnostic, filemap,
                                              sess.interner);

          Ok(Parser(sess, cfg, srdr as reader))

      }
      result::Err(move e) => Err(move e)
    }
}

/// Create a new parser for an entire crate, handling errors as appropriate
/// if the file doesn't exist
fn new_crate_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                              path: &Path) -> Parser {
    match new_parser_from_file(sess, cfg, path) {
        Ok(move parser) => move parser,
        Err(move e) => {
            sess.span_diagnostic.handler().fatal(e)
        }
    }
}

/// Create a new parser based on a span from an existing parser. Handles
/// error messages correctly when the file does not exist.
fn new_sub_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg,
                            path: &Path, sp: span) -> Parser {
    match new_parser_from_file(sess, cfg, path) {
        Ok(move parser) => move parser,
        Err(move e) => {
            sess.span_diagnostic.span_fatal(sp, e)
        }
    }
}

fn new_parser_from_tts(sess: parse_sess, cfg: ast::crate_cfg,
                       tts: ~[ast::token_tree]) -> Parser {
    let trdr = lexer::new_tt_reader(sess.span_diagnostic, sess.interner,
                                    None, tts);
    return Parser(sess, cfg, trdr as reader)
}
<|endoftext|>


<commit_before><commit_msg>Get serial number, firmware version, name from ATA<commit_after><|endoftext|>


<commit_before><commit_msg>Fix: Allow second to be missing<commit_after><|endoftext|>


<commit_before><commit_msg>Add ID reporting in imag-ids<commit_after><|endoftext|>


<commit_before><commit_msg>pattern/codegen: oh hey there's this thing; utility questionable<commit_after>//! Various helpers for code-generation.

use std::io;
use std::cmp;
use std::char;
use std::iter;
use std::usize;
use std::ops::{Add, AddAssign, Range};
#[cfg(test)]
use std::iter::FromIterator;

use super::{Atom, Class, ClassMember};

// ================================================================
/// Interface for types which can bound the number of bytes required to match
/// a particular instance of themselves.
pub trait SizedRead {
    /// Get the size of this object when read directly from something
    /// implementing `std::io::Read`.
    fn read_size(&self) -> ReadSize;
}

/// Trait for use with fixed-size types
pub trait ReadToBuffer {
    /// Read at most `max_count` instances of this atom type from the given
    /// stream, placing them into the supplied buffer.
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read;
}

/// Possible results from `SizedRead::read_size`
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ReadSize {
    /// Exact size is known in advance
    Exact(usize),

    /// Size can be within the given range of values.
    Range(usize, usize)
}

impl ReadSize {
    /// Get the minimum number of bytes specified by this ReadSize.
    #[inline]
    fn min(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(a, _) => a,
        }
    }
    /// Get the maximum number of bytes specified by this ReadSize.
    #[inline]
    fn max(&self) -> usize {
        match self {
            &ReadSize::Exact(s) => s,
            &ReadSize::Range(_, b) => b,
        }
    }

}

impl iter::Sum<ReadSize> for ReadSize {
    #[inline]
    fn sum<I>(iter: I) -> Self where I: Iterator<Item=ReadSize> {
        let mut sum = ReadSize::Exact(0);
        for rs in iter {
            sum += rs;
        }
        sum
    }
}

impl Add<ReadSize> for ReadSize {
    type Output = ReadSize;
    #[inline]
    fn add(self, rhs: ReadSize) -> Self::Output {
        let min = self.min() + rhs.min();
        let max = self.max() + rhs.max();
        if min == max { ReadSize::Exact(min) }
        else { ReadSize::Range(min, max) }
    }
}

impl AddAssign<ReadSize> for ReadSize {
    #[inline]
    fn add_assign(&mut self, rhs: ReadSize) {
        *self = *self + rhs;
    }
}

impl From<usize> for ReadSize {
    #[inline]
    fn from(s: usize) -> Self {
        ReadSize::Exact(s)
    }
}

impl From<Range<usize>> for ReadSize {
    #[inline]
    fn from(r: Range<usize>) -> Self {
        if r.len() > 1 { ReadSize::Range(r.start, r.end - 1) }
        else { ReadSize::Exact(r.start) }
    }
}

// ----------------------------------------------------------------
// Implementations

// This table was copied from the Rust source tree,
// file "src/libcore/str/mod.rs".
// https://tools.ietf.org/html/rfc3629
static UTF8_CHAR_WIDTH: [u8; 256] = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF
0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF
4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF
];

impl SizedRead for char {
    #[inline]
    fn read_size(&self) -> ReadSize {
        self.len_utf8().into()
    }
}

impl ReadToBuffer for char {
    #[inline]
    fn read_to_buffer<R>(r: &mut R, dest: &mut [u8], max_count: usize) -> io::Result<usize>
        where R: io::Read {
        let mut i = 0;
        let mut n = 0;
        while i < dest.len() && n < max_count {
            try!(r.read_exact(&mut dest[i..(i+1)]));
            let w = UTF8_CHAR_WIDTH[dest[i] as usize];
            try!(r.read_exact(&mut dest[(i+1)..(i + w as usize)]));
            i += w as usize;
            n += 1;
        }
        Ok(i)
    }

}

#[cfg(test)]
#[test]
fn test_sizedread_char() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
}

#[cfg(test)]
#[test]
fn test_readable_char() {
    let mut buf = ['\0' as u8; 32];
    {
        let mut r = io::repeat('a' as u8);
        assert_eq!(3, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(&['a' as u8 as u8, 'a' as u8, 'a' as u8, '\0' as u8], &buf[0..4]);
    }

    {
        let s = "✓☠⚔";
        let mut r = io::Cursor::new(s.as_bytes());
        assert_eq!(9, char::read_to_buffer(&mut r, &mut buf, 3).unwrap());
        assert_eq!(s.as_bytes(), &buf[0..9]);
    }
}

// ----------------------------------------------------------------

/*impl<T> SizedRead for Transition<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &Transition::Atom(a) => a.read_size(),
            &Transition::Literal(ref atoms) => atoms.iter().map(|a| a.read_size()).sum(),
            &Transition::Wildcard => ReadSize::Range(1, 4),
            &Transition::Anchor(..) => ReadSize::Exact(0),
            &Transition::Class(ref c) => c.read_size(),
        }
    }
}*/

#[cfg(test)]
#[test]
fn test_sizedread_transition() {
    assert_eq!(ReadSize::Exact(1), 'a'.read_size());
    assert_eq!(ReadSize::Exact(3), '✓'.read_size());
    assert_eq!(ReadSize::Range(1, 3), Class::from_iter(['x', 'y', '⚔'].into_iter().cloned()).read_size());
}

// ----------------------------------------------------------------

impl<T> SizedRead for ClassMember<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        match self {
            &ClassMember::Atom(a) => a.read_size(),
            &ClassMember::Range(first, last) => {
                // We'll assume that any differences in read size between
                // `first` and `last` follow a linear function between the two;
                // this _assumption_ allows us to avoid evaluating `read_size`
                // for every single member of the range.
                let frs = first.read_size();
                let lrs = last.read_size();
                (cmp::min(frs.min(), lrs.min())..(cmp::max(frs.max(), lrs.max()) + 1)).into()
            }
        }
    }
}

impl<T> SizedRead for Class<T>
    where T: Atom + SizedRead
{
    fn read_size(&self) -> ReadSize {
        let mut min = usize::MAX;
        let mut max = usize::MIN;

        for m in self.iter_members() {
            let rs = m.read_size();
            min = cmp::min(min, rs.min());
            max = cmp::max(max, rs.max());
        }

        (min..(max + 1)).into()
    }
}

<|endoftext|>


<commit_before><commit_msg>Add examples/ttx_diff<commit_after>//! print the ttx diff of two font files

use std::path::Path;

/// max non-diff lines to print; after this we skip to the next difference.
const MAX_SAME_TO_PRINT: usize = 100;

fn main() {
    let args = match flags::Args::from_env() {
        Ok(args) => args,
        Err(e) => {
            eprintln!("{e}");
            std::process::exit(1);
        }
    };

    let ttx1 = get_ttx(&args.path1, &args.tables);
    let ttx2 = get_ttx(&args.path2, &args.tables);

    assert_eq_str!(ttx1, ttx2)
}

fn get_ttx(path: &Path, args: &[String]) -> String {
    eprintln!("getting ttx for path {}, tables {args:?}", path.display());
    let ttx_path = path.with_extension("ttx");
    let _ = std::fs::remove_file(&ttx_path);
    let mut cmd = std::process::Command::new("ttx");
    for table in args {
        cmd.arg("-t").arg(table);
    }
    let status = cmd.arg(path).output().unwrap();
    if !status.status.success() {
        panic!("ttx dump failed");
    }

    assert!(ttx_path.exists());

    let r = std::fs::read_to_string(&ttx_path).unwrap();
    std::fs::remove_file(&ttx_path).unwrap();
    eprintln!("done :)");
    r
}

mod flags {
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required path1: PathBuf
            required path2: PathBuf
            {
                repeated -t, --tables tables: String
            }

    }
}

mod pretty_diff {
    use std::fmt;

    use ansi_term::{
        Colour::{Fixed, Green, Red},
        Style,
    };

    use super::MAX_SAME_TO_PRINT;

    const SIGN_RIGHT: char = '>'; // + > →
    const SIGN_LEFT: char = '<'; // - < ←

    #[macro_export]
    macro_rules! assert_eq_str {
    ($left:expr, $right:expr$(,)?) => ({
        assert_eq_str!(@ $left, $right, "", "");
    });
    ($left:expr, $right:expr, $($arg:tt)*) => ({
        assert_eq_str!(@ $left, $right, ": ", $($arg)+);
    });
    (@ $left:expr, $right:expr, $maybe_semicolon:expr, $($arg:tt)*) => ({
        match (&($left), &($right)) {
            (left, right) => {
                if !(*left == *right) {
                    ::std::panic!("assertion failed: `(left == right)`{}{}\
                       \n\
                       \n{}\
                       \n",
                       $maybe_semicolon,
                       format_args!($($arg)*),
                       pretty_diff::MyStrs { left, right }
                    )
                }
            }
        }
    });
}

    macro_rules! paint {
    ($f:expr, $colour:expr, $fmt:expr, $($args:tt)*) => (
        write!($f, "{}", $colour.paint(format!($fmt, $($args)*)))
    )
}

    pub(crate) struct MyStrs<'a> {
        pub(crate) left: &'a str,
        pub(crate) right: &'a str,
    }

    impl std::fmt::Display for MyStrs<'_> {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
            write_line_diff(f, self.left, self.right)
        }
    }

    /// Present the diff output for two mutliline strings in a pretty, colorised manner.
    pub fn write_line_diff<TWrite: fmt::Write>(
        f: &mut TWrite,
        left: &str,
        right: &str,
    ) -> fmt::Result {
        let diff = ::diff::lines(left, right);

        let mut changes = diff.into_iter().peekable();
        let mut previous_deletion = LatentDeletion::default();
        let mut seen_same = 0usize;

        let flush_seen = |f: &mut TWrite, seen: &mut usize| {
            if *seen > MAX_SAME_TO_PRINT {
                writeln!(f, "skipped {} lines", *seen - MAX_SAME_TO_PRINT).unwrap();
            }
            *seen = 0;
        };

        while let Some(change) = changes.next() {
            match (change, changes.peek()) {
                // If the text is unchanged, just print it plain
                (::diff::Result::Both(value, _), _) => {
                    previous_deletion.flush(f)?;
                    seen_same += 1;
                    if seen_same < MAX_SAME_TO_PRINT {
                        writeln!(f, " {}", value)?;
                    }
                }
                // Defer any deletions to next loop
                (::diff::Result::Left(deleted), _) => {
                    flush_seen(f, &mut seen_same);
                    previous_deletion.flush(f)?;
                    previous_deletion.set(deleted);
                }
                // Underlying diff library should never return this sequence
                (::diff::Result::Right(_), Some(::diff::Result::Left(_))) => {
                    panic!("insertion followed by deletion");
                }
                // If we're being followed by more insertions, don't inline diff
                (::diff::Result::Right(inserted), Some(::diff::Result::Right(_))) => {
                    flush_seen(f, &mut seen_same);
                    previous_deletion.flush(f)?;
                    paint!(f, Green, "{}{}", SIGN_RIGHT, inserted)?;
                    writeln!(f)?;
                }
                // Otherwise, check if we need to inline diff with the previous line (if it was a deletion)
                (::diff::Result::Right(inserted), _) => {
                    flush_seen(f, &mut seen_same);
                    if let Some(deleted) = previous_deletion.take() {
                        write_inline_diff(f, deleted, inserted)?;
                    } else {
                        previous_deletion.flush(f)?;
                        paint!(f, Green, "{}{}", SIGN_RIGHT, inserted)?;
                        writeln!(f)?;
                    }
                }
            };
        }

        flush_seen(f, &mut seen_same);
        previous_deletion.flush(f)?;
        Ok(())
    }

    /// Delay formatting this deleted chunk until later.
    ///
    /// It can be formatted as a whole chunk by calling `flush`, or the inner value
    /// obtained with `take` for further processing.
    #[derive(Default)]
    struct LatentDeletion<'a> {
        // The most recent deleted line we've seen
        value: Option<&'a str>,
        // The number of deleted lines we've seen, including the current value
        count: usize,
    }

    impl<'a> LatentDeletion<'a> {
        /// Set the chunk value.
        fn set(&mut self, value: &'a str) {
            self.value = Some(value);
            self.count += 1;
        }

        /// Take the underlying chunk value, if it's suitable for inline diffing.
        ///
        /// If there is no value of we've seen more than one line, return `None`.
        fn take(&mut self) -> Option<&'a str> {
            if self.count == 1 {
                self.value.take()
            } else {
                None
            }
        }

        /// If a value is set, print it as a whole chunk, using the given formatter.
        ///
        /// If a value is not set, reset the count to zero (as we've called `flush` twice,
        /// without seeing another deletion. Therefore the line in the middle was something else).
        fn flush<TWrite: fmt::Write>(&mut self, f: &mut TWrite) -> fmt::Result {
            if let Some(value) = self.value {
                paint!(f, Red, "{}{}", SIGN_LEFT, value)?;
                writeln!(f)?;
                self.value = None;
            } else {
                self.count = 0;
            }

            Ok(())
        }
    }

    /// Group character styling for an inline diff, to prevent wrapping each single
    /// character in terminal styling codes.
    ///
    /// Styles are applied automatically each time a new style is given in `write_with_style`.
    struct InlineWriter<'a, Writer> {
        f: &'a mut Writer,
        style: Style,
    }

    impl<'a, Writer> InlineWriter<'a, Writer>
    where
        Writer: fmt::Write,
    {
        fn new(f: &'a mut Writer) -> Self {
            InlineWriter {
                f,
                style: Style::new(),
            }
        }

        /// Push a new character into the buffer, specifying the style it should be written in.
        fn write_with_style(&mut self, c: &char, style: Style) -> fmt::Result {
            // If the style is the same as previously, just write character
            if style == self.style {
                write!(self.f, "{}", c)?;
            } else {
                // Close out previous style
                write!(self.f, "{}", self.style.suffix())?;

                // Store new style and start writing it
                write!(self.f, "{}{}", style.prefix(), c)?;
                self.style = style;
            }
            Ok(())
        }

        /// Finish any existing style and reset to default state.
        fn finish(&mut self) -> fmt::Result {
            // Close out previous style
            writeln!(self.f, "{}", self.style.suffix())?;
            self.style = Default::default();
            Ok(())
        }
    }

    /// Format a single line to show an inline diff of the two strings given.
    ///
    /// The given strings should not have a trailing newline.
    ///
    /// The output of this function will be two lines, each with a trailing newline.
    fn write_inline_diff<TWrite: fmt::Write>(
        f: &mut TWrite,
        left: &str,
        right: &str,
    ) -> fmt::Result {
        let diff = ::diff::chars(left, right);
        let mut writer = InlineWriter::new(f);

        // Print the left string on one line, with differences highlighted
        let light = Red.into();
        let heavy = Red.on(Fixed(52)).bold();
        writer.write_with_style(&SIGN_LEFT, light)?;
        for change in diff.iter() {
            match change {
                ::diff::Result::Both(value, _) => writer.write_with_style(value, light)?,
                ::diff::Result::Left(value) => writer.write_with_style(value, heavy)?,
                _ => (),
            }
        }
        writer.finish()?;

        // Print the right string on one line, with differences highlighted
        let light = Green.into();
        let heavy = Green.on(Fixed(22)).bold();
        writer.write_with_style(&SIGN_RIGHT, light)?;
        for change in diff.iter() {
            match change {
                ::diff::Result::Both(value, _) => writer.write_with_style(value, light)?,
                ::diff::Result::Right(value) => writer.write_with_style(value, heavy)?,
                _ => (),
            }
        }
        writer.finish()
    }
}
<|endoftext|>


<commit_before><commit_msg>Change the type of optargs in protocol structs<commit_after><|endoftext|>


<commit_before><commit_msg>Rewrite closure for more structured and easy-to-read code<commit_after><|endoftext|>


<commit_before><commit_msg>Add a cycle-collection fuzzer<commit_after>use std;
import std::vec;
import std::rand;
import std::option;

// random uint less than n
fn under(r : rand::rng, n : uint) -> uint { assert n != 0u; r.next() as uint % n }

// random choice from a vec
fn choice<T>(r : rand::rng, v : [T]) -> T { assert vec::len(v) != 0u; v[under(r, vec::len(v))] }

// 1 in n chance of being true
fn unlikely(r : rand::rng, n : uint) -> bool { under(r, n) == 0u }

tag maybe_pointy {
  no_pointy;
  yes_pointy(@pointy);
}

type pointy = {
  mutable x : maybe_pointy,
  mutable y : maybe_pointy,
  mutable z : fn()->()
};

iter allunder(n: uint) -> uint {
    let i: uint = 0u;
    while i < n { put i; i += 1u; }
}

fn nopT(_x : @pointy) { }
fn nop() { }

fn test_cycles(r : rand::rng)
{
    const max : uint = 10u;

    let v : [mutable @pointy] = [mutable];
    for each i in allunder(max) {
        v += [mutable @{ mutable x : no_pointy, mutable y : no_pointy, mutable z: nop }];
    }

    for each i in allunder(max) {
        v[i].x = yes_pointy(v[under(r, max)]);
        v[i].y = yes_pointy(v[under(r, max)]);
        v[i].z = bind nopT(v[under(r, max)]);
    }

    // Drop refs one at a time
    for each i in allunder(max) {
        v[i] = @{ mutable x : no_pointy, mutable y : no_pointy, mutable z: nop };
    }
}

fn main()
{
    let r = rand::mk_rng();
    test_cycles(r);
}
<|endoftext|>


<commit_before><commit_msg>Add first code dump for annotation module<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreId;

use result::Result;
use error::AnnotationErrorKind as AEK;

use module_path::ModuleEntryPath;

pub trait Annotateable {

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    fn annotate(&self, store: &Store) -> Result<Annotation> {
        self.annotate_with_path_generator(store, DefaultAnnotationPathGenerator::new())
    }

    /// Add an annotation to `Self`, that is a `FileLockEntry` which is linked to `Self` (link as in
    /// libimagentrylink).
    ///
    /// This `Annotation` is stored in the Store itself.
    ///
    /// The `pg` is a AnnotationPathGenerator object which is used to generate a StoreId
    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator) -> Result<Annotation>;

}

/// A AnnotationPathGenerator generates a unique path for the annotation to be generated.
pub trait AnnotationPathGenerator {
    fn generate_annotation_path(&self) -> Result<StoreId>;
}

/// The DefaultAnnotationPathGenerator generates unique StoreIds for Annotations, where the
/// collection the annotations are stored in is `/annotation/`.
pub struct DefaultAnnotationPathGenerator;

impl AnnotationPathGenerator for DefaultAnnotationPathGenerator {

    fn generate_annotation_path(&self) -> Result<StoreId> {
        let id = Uuid::new_v4();
        ModuleEntryPath::new(format!("{}", id)).map_err_into(AEK::StoreIdGenerationError)
    }

}

pub struct Annotation<'a>(FileLockEntry<'a>);

impl Annotateable for FileLockEntry {

    fn annotate_with_path_generator(&self, store: &Store, pg: &AnnotationPathGenerator)
        -> Result<Annotation>
    {
    }
}
<|endoftext|>


<commit_before>use std::char;
use std::num::ParseIntError;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Counter(String, u64),
    Gauge(String, u64),
    Timer(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

fn bytes_to_u64(i: &[u8]) -> Result<u64, ParseIntError> {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s)
}

pub fn parse_counter(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|c") ~
        sample_rate: opt!(complete!(parse_sample_rate)) ,

        ||{ ParsedMetric::Counter(name, value) }
    )
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, value) }
    )
}

pub fn parse_timer(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|ms") ,

        ||{ ParsedMetric::Timer(name, value) }
    )
}

pub fn parse_value(i: &[u8]) -> IResult<&[u8], u64> {
    map_res!(i,
        digit,
        |value| { bytes_to_u64(value) }
    )
}

pub fn parse_sample_rate(i: &[u8]) -> IResult<&[u8], u64> {
    preceded!(i,
        tag!("|@"),
        map_res!(digit, |rate| { bytes_to_u64(rate) })
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

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

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:12|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parses_counter() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:23|c"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 23))
        )
    }

    #[test]
    fn it_parses_counter_with_sample_rate() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:34|c|@5"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 34))
        )
    }

    #[test]
    fn it_parses_timer() {
        assert_eq!(
            parse_timer(&b"foo.bar_baz:12|ms"[..]),
            complete(ParsedMetric::Timer("foo.bar_baz".to_owned(), 12))
        )
    }
}
<commit_msg>Full parsing of StatsD messages<commit_after>use std::char;
use std::error;
use std::fmt;
use std::num::ParseIntError;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Counter(String, u64),
    Gauge(String, u64),
    Timer(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

// Convert a byte array to a `u64` result.
fn bytes_to_u64(i: &[u8]) -> Result<u64, ParseIntError> {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s)
}

#[derive(Debug, PartialEq)]
pub struct ParseError {
    description: String,
}

impl fmt::Display for ParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description)
    }
}

impl error::Error for ParseError {
    fn description(&self) -> &str {
        &self.description
    }
}

pub fn parse_metrics(i: &[u8]) -> Result<Vec<ParsedMetric>, ParseError> {
    let result = complete!(i,
        separated_nonempty_list!(
            tag!("\n"),
            alt_complete!(
                parse_counter |
                parse_gauge |
                parse_timer
            )
        )
    );

    match result {
        IResult::Done(_, metrics) => Ok(metrics),
        IResult::Error(err) => Err(ParseError { description: format!("{:?}", err) }),
        IResult::Incomplete(_) => unreachable!("Cannot be Incomplete"),
    }
}

pub fn parse_counter(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|c") ~
        _sample_rate: opt!(complete!(parse_sample_rate)) ,

        ||{ ParsedMetric::Counter(name, value) }
    )
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, value) }
    )
}

pub fn parse_timer(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|ms") ,

        ||{ ParsedMetric::Timer(name, value) }
    )
}

pub fn parse_value(i: &[u8]) -> IResult<&[u8], u64> {
    map_res!(i,
        digit,
        |value| { bytes_to_u64(value) }
    )
}

pub fn parse_sample_rate(i: &[u8]) -> IResult<&[u8], u64> {
    preceded!(i,
        tag!("|@"),
        map_res!(digit, |rate| { bytes_to_u64(rate) })
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

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

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:12|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parses_counter() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:23|c"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 23))
        )
    }

    #[test]
    fn it_parses_counter_with_sample_rate() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:34|c|@5"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 34))
        )
    }

    #[test]
    fn it_parses_timer() {
        assert_eq!(
            parse_timer(&b"foo.bar_baz:12|ms"[..]),
            complete(ParsedMetric::Timer("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parse_single_metric() {
        assert_eq!(
            parse_metrics(&b"foo:1|g"[..]),
            Ok(vec![
                ParsedMetric::Gauge("foo".to_owned(), 1),
            ])
        )
    }

    #[test]
    fn it_parse_many_metrics() {
        assert_eq!(
            parse_metrics(&b"foo:1|g\nbar:2|c|@3\nbaz:4|ms"[..]),
            Ok(vec![
                ParsedMetric::Gauge("foo".to_owned(), 1),
                ParsedMetric::Counter("bar".to_owned(), 2),
                ParsedMetric::Timer("baz".to_owned(), 4),
            ])
        )
    }
}
<|endoftext|>


<commit_before><commit_msg>Simplify implementation<commit_after><|endoftext|>


<commit_before><commit_msg>Add trait for single unlocking of an item<commit_after>pub trait SingleUseLock<T> {
    fn access(&self) -> &T;
    fn unlock(self) -> T;
}

<|endoftext|>


<commit_before><commit_msg>replace String::from_raw_buf<commit_after><|endoftext|>


<commit_before><commit_msg>Remove unused code from the library<commit_after><|endoftext|>


<commit_before><commit_msg>`xaudio2.h` constants<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests for cookie overwriting on same "identity".<commit_after><|endoftext|>


<commit_before><commit_msg>Remove syntax error.<commit_after><|endoftext|>


<commit_before><commit_msg>Hashable resource sets and minor spacing<commit_after><|endoftext|>


<commit_before><commit_msg>Change for loops to folds, match branches<commit_after><|endoftext|>


<commit_before><commit_msg>Adding TaskSystem trait and move serial task code over<commit_after>//! Defines the trait that must be implemented by ISPC task execution systems
//! and provides a default threaded one for use.

use libc;

use std::mem;
use std::sync::Arc;
use std::sync::atomic::{self, AtomicUsize};

use task::{ISPCTaskFn, Context};

/// Trait to be implemented to provide ISPC task execution functionality.
///
/// The runtime [required functions](http://ispc.github.io/ispc.html#task-parallelism-runtime-requirements)
/// will be forwarded directly to your struct, making this interface unsafe.
pub trait TaskSystem {
    /// Alloc is called when memory must be allocated to store parameters to pass to a task
    /// and must return a pointer to an allocation of `size` bytes aligned to `align`.
    ///
    /// The `handle_ptr` will be `NULL` if this is the first time launch has been called in
    /// the function or is the first launch call after an explicit `sync` statement. Both
    /// situations should be treated equivalently as creating a new exeuction context for tasks.
    /// The `handle_ptr` should be set to some context tracking facility so that you can later
    /// track task groups launched in the context and perform finer grained synchronization in
    /// `sync`.
    unsafe fn alloc(&mut self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void;
    /// Launch is called when a new group of tasks is being launched and should schedule them to
    /// be executed in some way.
    ///
    /// The `handle_ptr` will point to the same handle you set up in `alloc` and can be used to
    /// associate groups of tasks with a context of execution as mentioned before. The function `f`
    /// should be executed `count0 * count1 * count2` times and indices passed to the function
    /// should be as if running in a nested for loop:
    ///
    /// ```no_compile
    /// let total_tasks = count0 * count1 * count2;
    /// for z in 0..count2 {
    ///     for y in 0..count1 {
    ///         for x in 0..count0 {
    ///             let task_id = x + y * count0 + z * count0 * count1;
    ///             f(data, thread_id, total_threads, task_id, total_tasks,
    ///               x, y, z, count0, count1, count2);
    ///         }
    ///     }
    /// }
    /// ```
    ///
    /// The `data` pointer points to the ISPC task specific parameter pointer and should be passed
    /// through to the function.
    unsafe fn launch(&mut self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32);
    /// Synchronize an execution context with the tasks it's launched. Use `handle` to determine
    /// the task context being synchronized.
    ///
    /// This function should not return until all tasks launched within the context being
    /// synchronized with have been completed. You can use the `handle` to determine which context
    /// is being synchronized with and thus which tasks must be completed before returning.
    unsafe fn sync(&mut self, handle: *mut libc::c_void);
}

/// A simple serial execution environment for the tasks.
pub struct Serial {
    context_list: Vec<Arc<Context>>,
    next_context_id: AtomicUsize,
}

impl Serial {
    pub fn new() -> Serial {
        Serial { context_list: Vec::new(), next_context_id: AtomicUsize::new(0) }
    }
}

impl TaskSystem for Serial {
    unsafe fn alloc(&mut self, handle_ptr: *mut *mut libc::c_void, size: i64, align: i32) -> *mut libc::c_void {
        println!("ISPCAlloc, size: {}, align: {}", size, align);
        // If the handle is null this is the first time this function has spawned tasks
        // and we should create a new Context structure in the TASK_LIST for it, otherwise
        // it's the pointer to where we should append the new Group
        let context = if (*handle_ptr).is_null() {
            println!("handle ptr is null");
            // This is a bit hairy. We allocate the new task context in a box, then
            // unbox it into a raw ptr to get a ptr we can pass back to ISPC through
            // the handle_ptr and then re-box it into our TASK_LIST so it will
            // be free'd properly when we erase it from the vector in ISPCSync
            let c = Arc::new(Context::new(self.next_context_id.fetch_add(1, atomic::Ordering::SeqCst)));
            {
                let h = &*c;
                *handle_ptr = mem::transmute(h);
            }
            self.context_list.push(c);
            self.context_list.last_mut().unwrap()
        } else {
            println!("handle ptr is not null");
            let handle_ctx: *mut Context = mem::transmute(*handle_ptr);
            self.context_list.iter_mut().find(|c| (*handle_ctx).id == c.id).unwrap()
        };
        println!("context.id = {}", context.id);
        context.alloc(size as usize, align as usize)
    }
    unsafe fn launch(&mut self, handle_ptr: *mut *mut libc::c_void, f: ISPCTaskFn, data: *mut libc::c_void,
                     count0: i32, count1: i32, count2: i32) {
        // Push the tasks being launched on to the list of task groups for this function
        let context: &mut Context = mem::transmute(*handle_ptr);
        println!("ISPCLaunch, context.id = {}, counts: [{}, {}, {}]", context.id, count0, count1, count2);
        context.launch((count0, count1, count2), data, f);
    }
    unsafe fn sync(&mut self, handle: *mut libc::c_void) {
        let context: &mut Context = mem::transmute(handle);
        // Make sure all tasks are done, and execute them if not for this simple
        // serial version. TODO: In the future we'd wait on each Group's semaphore or atomic bool
        // Maybe the waiting thread could help execute tasks as well, otherwise it might be
        // possible to deadlock, where all threads are waiting for some enqueue'd tasks but no
        // threads are available to run them. Just running tasks in our context is not sufficient
        // to prevent deadlock actually, because those tasks could in turn launch & sync and get stuck
        // so if our tasks aren't done and there's none left to run in our context we should start
        // running tasks from other contexts to help out
        println!("ISPCSync, context.id = {}", context.id);
        for tg in context.iter() {
            for chunk in tg.chunks(4) {
                println!("Running chunk {:?}", chunk);
                chunk.execute(0, 1);
            }
        }
        // TODO: If all the tasks for this context have been finished we're done sync'ing and can
        // clean up memory and remove the context from the TASK_LIST. Otherwise there are some
        // unfinished groups further down the the tree that were spawned by our direct tasks that
        // those are now sync'ing on and we need to help out. However since we don't know the tree
        // our best option is to just start grabbing chunks from unfinished groups in the TASK_LIST
        // and running them to at least ensure global forward progress, which will eventually get
        // the stuff we're waiting on to finish. After each chunk execution we should check if
        // our sync'ing context is done and break
        if context.current_tasks_done() {
            println!("All tasks for context id {} are done!", context.id);
        }
        // Now erase this context from our vector
        let pos = self.context_list.iter().position(|c| context.id == c.id).unwrap();
        self.context_list.remove(pos);
    }
}

<|endoftext|>


<commit_before><commit_msg> removed filter for testing<commit_after><|endoftext|>