<commit_before>use uucore::display::Quotable;

use crate::options::{NumfmtOptions, RoundMethod};
use crate::units::{DisplayableSuffix, RawSuffix, Result, Suffix, Unit, IEC_BASES, SI_BASES};

/// Iterate over a line's fields, where each field is a contiguous sequence of
/// non-whitespace, optionally prefixed with one or more characters of leading
/// whitespace. Fields are returned as tuples of `(prefix, field)`.
///
/// # Examples:
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
///
/// assert_eq!(Some(("    ", "1234")), fields.next());
/// assert_eq!(Some((" ", "5")), fields.next());
/// assert_eq!(None, fields.next());
/// ```
///
/// Delimiters are included in the results; `prefix` will be empty only for
/// the first field of the line (including the case where the input line is
/// empty):
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
///
/// assert_eq!(Some(("", "first")), fields.next());
/// assert_eq!(Some((" ", "second")), fields.next());
///
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
///
/// assert_eq!(Some(("", "")), fields.next());
/// ```
pub struct WhitespaceSplitter<'a> {
    pub s: Option<&'a str>,
}

impl<'a> Iterator for WhitespaceSplitter<'a> {
    type Item = (&'a str, &'a str);

    /// Yield the next field in the input string as a tuple `(prefix, field)`.
    fn next(&mut self) -> Option<Self::Item> {
        let haystack = self.s?;

        let (prefix, field) = haystack.split_at(
            haystack
                .find(|c: char| !c.is_whitespace())
                .unwrap_or(haystack.len()),
        );

        let (field, rest) = field.split_at(
            field
                .find(|c: char| c.is_whitespace())
                .unwrap_or(field.len()),
        );

        self.s = if !rest.is_empty() { Some(rest) } else { None };

        Some((prefix, field))
    }
}

fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
    if s.is_empty() {
        return Err("invalid number: ''".to_string());
    }

    let with_i = s.ends_with('i');
    let mut iter = s.chars();
    if with_i {
        iter.next_back();
    }
    let suffix = match iter.next_back() {
        Some('K') => Some((RawSuffix::K, with_i)),
        Some('M') => Some((RawSuffix::M, with_i)),
        Some('G') => Some((RawSuffix::G, with_i)),
        Some('T') => Some((RawSuffix::T, with_i)),
        Some('P') => Some((RawSuffix::P, with_i)),
        Some('E') => Some((RawSuffix::E, with_i)),
        Some('Z') => Some((RawSuffix::Z, with_i)),
        Some('Y') => Some((RawSuffix::Y, with_i)),
        Some('0'..='9') => None,
        _ => return Err(format!("invalid suffix in input: {}", s.quote())),
    };

    let suffix_len = match suffix {
        None => 0,
        Some((_, false)) => 1,
        Some((_, true)) => 2,
    };

    let number = s[..s.len() - suffix_len]
        .parse::<f64>()
        .map_err(|_| format!("invalid number: {}", s.quote()))?;

    Ok((number, suffix))
}

fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
    match (s, u) {
        (None, _) => Ok(i),
        (Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
            match raw_suffix {
                RawSuffix::K => Ok(i * 1e3),
                RawSuffix::M => Ok(i * 1e6),
                RawSuffix::G => Ok(i * 1e9),
                RawSuffix::T => Ok(i * 1e12),
                RawSuffix::P => Ok(i * 1e15),
                RawSuffix::E => Ok(i * 1e18),
                RawSuffix::Z => Ok(i * 1e21),
                RawSuffix::Y => Ok(i * 1e24),
            }
        }
        (Some((raw_suffix, false)), &Unit::Iec(false))
        | (Some((raw_suffix, true)), &Unit::Auto)
        | (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
            RawSuffix::K => Ok(i * IEC_BASES[1]),
            RawSuffix::M => Ok(i * IEC_BASES[2]),
            RawSuffix::G => Ok(i * IEC_BASES[3]),
            RawSuffix::T => Ok(i * IEC_BASES[4]),
            RawSuffix::P => Ok(i * IEC_BASES[5]),
            RawSuffix::E => Ok(i * IEC_BASES[6]),
            RawSuffix::Z => Ok(i * IEC_BASES[7]),
            RawSuffix::Y => Ok(i * IEC_BASES[8]),
        },
        (_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
    }
}

fn transform_from(s: &str, opts: &Unit) -> Result<f64> {
    let (i, suffix) = parse_suffix(s)?;

    remove_suffix(i, suffix, opts).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
}

/// Divide numerator by denominator, with rounding.
///
/// If the result of the division is less than 10.0, round to one decimal point.
///
/// Otherwise, round to an integer.
///
/// # Examples:
///
/// ```
/// use uu_numfmt::format::div_round;
/// use uu_numfmt::options::RoundMethod;
///
/// // Rounding methods:
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::FromZero), 1.1);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::TowardsZero), 1.0);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Up), 1.1);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Down), 1.0);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Nearest), 1.0);
///
/// // Division:
/// assert_eq!(div_round(999.1, 1000.0, RoundMethod::FromZero), 1.0);
/// assert_eq!(div_round(1001., 10., RoundMethod::FromZero), 101.);
/// assert_eq!(div_round(9991., 10., RoundMethod::FromZero), 1000.);
/// assert_eq!(div_round(-12.34, 1.0, RoundMethod::FromZero), -13.0);
/// assert_eq!(div_round(1000.0, -3.14, RoundMethod::FromZero), -319.0);
/// assert_eq!(div_round(-271828.0, -271.0, RoundMethod::FromZero), 1004.0);
/// ```
pub fn div_round(n: f64, d: f64, method: RoundMethod) -> f64 {
    let v = n / d;

    if v.abs() < 10.0 {
        method.round(10.0 * v) / 10.0
    } else {
        method.round(v)
    }
}

fn consider_suffix(n: f64, u: &Unit, round_method: RoundMethod) -> Result<(f64, Option<Suffix>)> {
    use crate::units::RawSuffix::*;

    let abs_n = n.abs();
    let suffixes = [K, M, G, T, P, E, Z, Y];

    let (bases, with_i) = match *u {
        Unit::Si => (&SI_BASES, false),
        Unit::Iec(with_i) => (&IEC_BASES, with_i),
        Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
        Unit::None => return Ok((n, None)),
    };

    let i = match abs_n {
        _ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
        _ if abs_n < bases[2] => 1,
        _ if abs_n < bases[3] => 2,
        _ if abs_n < bases[4] => 3,
        _ if abs_n < bases[5] => 4,
        _ if abs_n < bases[6] => 5,
        _ if abs_n < bases[7] => 6,
        _ if abs_n < bases[8] => 7,
        _ if abs_n < bases[9] => 8,
        _ => return Err("Number is too big and unsupported".to_string()),
    };

    let v = div_round(n, bases[i], round_method);

    // check if rounding pushed us into the next base
    if v.abs() >= bases[1] {
        Ok((v / bases[1], Some((suffixes[i], with_i))))
    } else {
        Ok((v, Some((suffixes[i - 1], with_i))))
    }
}

fn transform_to(s: f64, opts: &Unit, round_method: RoundMethod) -> Result<String> {
    let (i2, s) = consider_suffix(s, opts, round_method)?;
    Ok(match s {
        None => format!("{}", i2),
        Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
        Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
    })
}

fn format_string(
    source: &str,
    options: &NumfmtOptions,
    implicit_padding: Option<isize>,
) -> Result<String> {
    // strip the (optional) suffix before applying any transformation
    let source_without_suffix = if let Some(suffix) = &options.suffix {
        source.strip_suffix(suffix).unwrap_or(source)
    } else {
        source
    };

    let number = transform_to(
        transform_from(source_without_suffix, &options.transform.from)?,
        &options.transform.to,
        options.round,
    )?;

    // bring back the suffix before applying padding
    let number_with_suffix = if let Some(suffix) = &options.suffix {
        format!("{}{}", number, suffix)
    } else {
        number
    };

    Ok(match implicit_padding.unwrap_or(options.padding) {
        0 => number_with_suffix,
        p if p > 0 => format!("{:>padding$}", number_with_suffix, padding = p as usize),
        p => format!(
            "{:<padding$}",
            number_with_suffix,
            padding = p.abs() as usize
        ),
    })
}

fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
    let delimiter = options.delimiter.as_ref().unwrap();

    for (n, field) in (1..).zip(s.split(delimiter)) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        // print delimiter before second and subsequent fields
        if n > 1 {
            print!("{}", delimiter);
        }

        if field_selected {
            print!("{}", format_string(field.trim_start(), options, None)?);
        } else {
            // print unselected field without conversion
            print!("{}", field);
        }
    }

    println!();

    Ok(())
}

fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
    for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        if field_selected {
            let empty_prefix = prefix.is_empty();

            // print delimiter before second and subsequent fields
            let prefix = if n > 1 {
                print!(" ");
                &prefix[1..]
            } else {
                prefix
            };

            let implicit_padding = if !empty_prefix && options.padding == 0 {
                Some((prefix.len() + field.len()) as isize)
            } else {
                None
            };

            print!("{}", format_string(field, options, implicit_padding)?);
        } else {
            // print unselected field without conversion
            print!("{}{}", prefix, field);
        }
    }

    println!();

    Ok(())
}

/// Format a line of text according to the selected options.
///
/// Given a line of text `s`, split the line into fields, transform and format
/// any selected numeric fields, and print the result to stdout. Fields not
/// selected for conversion are passed through unmodified.
pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
    match &options.delimiter {
        Some(_) => format_and_print_delimited(s, options),
        None => format_and_print_whitespace(s, options),
    }
}
<commit_msg>numfmt: replace if let with simpler match<commit_after>use uucore::display::Quotable;

use crate::options::{NumfmtOptions, RoundMethod};
use crate::units::{DisplayableSuffix, RawSuffix, Result, Suffix, Unit, IEC_BASES, SI_BASES};

/// Iterate over a line's fields, where each field is a contiguous sequence of
/// non-whitespace, optionally prefixed with one or more characters of leading
/// whitespace. Fields are returned as tuples of `(prefix, field)`.
///
/// # Examples:
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
///
/// assert_eq!(Some(("    ", "1234")), fields.next());
/// assert_eq!(Some((" ", "5")), fields.next());
/// assert_eq!(None, fields.next());
/// ```
///
/// Delimiters are included in the results; `prefix` will be empty only for
/// the first field of the line (including the case where the input line is
/// empty):
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
///
/// assert_eq!(Some(("", "first")), fields.next());
/// assert_eq!(Some((" ", "second")), fields.next());
///
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
///
/// assert_eq!(Some(("", "")), fields.next());
/// ```
pub struct WhitespaceSplitter<'a> {
    pub s: Option<&'a str>,
}

impl<'a> Iterator for WhitespaceSplitter<'a> {
    type Item = (&'a str, &'a str);

    /// Yield the next field in the input string as a tuple `(prefix, field)`.
    fn next(&mut self) -> Option<Self::Item> {
        let haystack = self.s?;

        let (prefix, field) = haystack.split_at(
            haystack
                .find(|c: char| !c.is_whitespace())
                .unwrap_or(haystack.len()),
        );

        let (field, rest) = field.split_at(
            field
                .find(|c: char| c.is_whitespace())
                .unwrap_or(field.len()),
        );

        self.s = if !rest.is_empty() { Some(rest) } else { None };

        Some((prefix, field))
    }
}

fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
    if s.is_empty() {
        return Err("invalid number: ''".to_string());
    }

    let with_i = s.ends_with('i');
    let mut iter = s.chars();
    if with_i {
        iter.next_back();
    }
    let suffix = match iter.next_back() {
        Some('K') => Some((RawSuffix::K, with_i)),
        Some('M') => Some((RawSuffix::M, with_i)),
        Some('G') => Some((RawSuffix::G, with_i)),
        Some('T') => Some((RawSuffix::T, with_i)),
        Some('P') => Some((RawSuffix::P, with_i)),
        Some('E') => Some((RawSuffix::E, with_i)),
        Some('Z') => Some((RawSuffix::Z, with_i)),
        Some('Y') => Some((RawSuffix::Y, with_i)),
        Some('0'..='9') => None,
        _ => return Err(format!("invalid suffix in input: {}", s.quote())),
    };

    let suffix_len = match suffix {
        None => 0,
        Some((_, false)) => 1,
        Some((_, true)) => 2,
    };

    let number = s[..s.len() - suffix_len]
        .parse::<f64>()
        .map_err(|_| format!("invalid number: {}", s.quote()))?;

    Ok((number, suffix))
}

fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
    match (s, u) {
        (None, _) => Ok(i),
        (Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
            match raw_suffix {
                RawSuffix::K => Ok(i * 1e3),
                RawSuffix::M => Ok(i * 1e6),
                RawSuffix::G => Ok(i * 1e9),
                RawSuffix::T => Ok(i * 1e12),
                RawSuffix::P => Ok(i * 1e15),
                RawSuffix::E => Ok(i * 1e18),
                RawSuffix::Z => Ok(i * 1e21),
                RawSuffix::Y => Ok(i * 1e24),
            }
        }
        (Some((raw_suffix, false)), &Unit::Iec(false))
        | (Some((raw_suffix, true)), &Unit::Auto)
        | (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
            RawSuffix::K => Ok(i * IEC_BASES[1]),
            RawSuffix::M => Ok(i * IEC_BASES[2]),
            RawSuffix::G => Ok(i * IEC_BASES[3]),
            RawSuffix::T => Ok(i * IEC_BASES[4]),
            RawSuffix::P => Ok(i * IEC_BASES[5]),
            RawSuffix::E => Ok(i * IEC_BASES[6]),
            RawSuffix::Z => Ok(i * IEC_BASES[7]),
            RawSuffix::Y => Ok(i * IEC_BASES[8]),
        },
        (_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
    }
}

fn transform_from(s: &str, opts: &Unit) -> Result<f64> {
    let (i, suffix) = parse_suffix(s)?;

    remove_suffix(i, suffix, opts).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
}

/// Divide numerator by denominator, with rounding.
///
/// If the result of the division is less than 10.0, round to one decimal point.
///
/// Otherwise, round to an integer.
///
/// # Examples:
///
/// ```
/// use uu_numfmt::format::div_round;
/// use uu_numfmt::options::RoundMethod;
///
/// // Rounding methods:
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::FromZero), 1.1);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::TowardsZero), 1.0);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Up), 1.1);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Down), 1.0);
/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Nearest), 1.0);
///
/// // Division:
/// assert_eq!(div_round(999.1, 1000.0, RoundMethod::FromZero), 1.0);
/// assert_eq!(div_round(1001., 10., RoundMethod::FromZero), 101.);
/// assert_eq!(div_round(9991., 10., RoundMethod::FromZero), 1000.);
/// assert_eq!(div_round(-12.34, 1.0, RoundMethod::FromZero), -13.0);
/// assert_eq!(div_round(1000.0, -3.14, RoundMethod::FromZero), -319.0);
/// assert_eq!(div_round(-271828.0, -271.0, RoundMethod::FromZero), 1004.0);
/// ```
pub fn div_round(n: f64, d: f64, method: RoundMethod) -> f64 {
    let v = n / d;

    if v.abs() < 10.0 {
        method.round(10.0 * v) / 10.0
    } else {
        method.round(v)
    }
}

fn consider_suffix(n: f64, u: &Unit, round_method: RoundMethod) -> Result<(f64, Option<Suffix>)> {
    use crate::units::RawSuffix::*;

    let abs_n = n.abs();
    let suffixes = [K, M, G, T, P, E, Z, Y];

    let (bases, with_i) = match *u {
        Unit::Si => (&SI_BASES, false),
        Unit::Iec(with_i) => (&IEC_BASES, with_i),
        Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
        Unit::None => return Ok((n, None)),
    };

    let i = match abs_n {
        _ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
        _ if abs_n < bases[2] => 1,
        _ if abs_n < bases[3] => 2,
        _ if abs_n < bases[4] => 3,
        _ if abs_n < bases[5] => 4,
        _ if abs_n < bases[6] => 5,
        _ if abs_n < bases[7] => 6,
        _ if abs_n < bases[8] => 7,
        _ if abs_n < bases[9] => 8,
        _ => return Err("Number is too big and unsupported".to_string()),
    };

    let v = div_round(n, bases[i], round_method);

    // check if rounding pushed us into the next base
    if v.abs() >= bases[1] {
        Ok((v / bases[1], Some((suffixes[i], with_i))))
    } else {
        Ok((v, Some((suffixes[i - 1], with_i))))
    }
}

fn transform_to(s: f64, opts: &Unit, round_method: RoundMethod) -> Result<String> {
    let (i2, s) = consider_suffix(s, opts, round_method)?;
    Ok(match s {
        None => format!("{}", i2),
        Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
        Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
    })
}

fn format_string(
    source: &str,
    options: &NumfmtOptions,
    implicit_padding: Option<isize>,
) -> Result<String> {
    // strip the (optional) suffix before applying any transformation
    let source_without_suffix = match &options.suffix {
        Some(suffix) => source.strip_suffix(suffix).unwrap_or(source),
        None => source,
    };

    let number = transform_to(
        transform_from(source_without_suffix, &options.transform.from)?,
        &options.transform.to,
        options.round,
    )?;

    // bring back the suffix before applying padding
    let number_with_suffix = match &options.suffix {
        Some(suffix) => format!("{}{}", number, suffix),
        None => number,
    };

    Ok(match implicit_padding.unwrap_or(options.padding) {
        0 => number_with_suffix,
        p if p > 0 => format!("{:>padding$}", number_with_suffix, padding = p as usize),
        p => format!(
            "{:<padding$}",
            number_with_suffix,
            padding = p.abs() as usize
        ),
    })
}

fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
    let delimiter = options.delimiter.as_ref().unwrap();

    for (n, field) in (1..).zip(s.split(delimiter)) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        // print delimiter before second and subsequent fields
        if n > 1 {
            print!("{}", delimiter);
        }

        if field_selected {
            print!("{}", format_string(field.trim_start(), options, None)?);
        } else {
            // print unselected field without conversion
            print!("{}", field);
        }
    }

    println!();

    Ok(())
}

fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
    for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
        let field_selected = uucore::ranges::contain(&options.fields, n);

        if field_selected {
            let empty_prefix = prefix.is_empty();

            // print delimiter before second and subsequent fields
            let prefix = if n > 1 {
                print!(" ");
                &prefix[1..]
            } else {
                prefix
            };

            let implicit_padding = if !empty_prefix && options.padding == 0 {
                Some((prefix.len() + field.len()) as isize)
            } else {
                None
            };

            print!("{}", format_string(field, options, implicit_padding)?);
        } else {
            // print unselected field without conversion
            print!("{}{}", prefix, field);
        }
    }

    println!();

    Ok(())
}

/// Format a line of text according to the selected options.
///
/// Given a line of text `s`, split the line into fields, transform and format
/// any selected numeric fields, and print the result to stdout. Fields not
/// selected for conversion are passed through unmodified.
pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
    match &options.delimiter {
        Some(_) => format_and_print_delimited(s, options),
        None => format_and_print_whitespace(s, options),
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Yury Krivopalov <ykrivopalov@yandex.ru>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore N'th M'th

use crate::errors::*;
use crate::format::format_and_print;
use crate::options::*;
use crate::units::{Result, Unit};
use clap::{crate_version, Arg, ArgMatches, Command};
use std::io::{BufRead, Write};
use uucore::display::Quotable;
use uucore::error::UResult;
use uucore::format_usage;
use uucore::ranges::Range;

pub mod errors;
pub mod format;
pub mod options;
mod units;

static ABOUT: &str = "Convert numbers from/to human-readable strings";
static LONG_HELP: &str = "UNIT options:
   none   no auto-scaling is done; suffixes will trigger an error

   auto   accept optional single/two letter suffix:

          1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,

   si     accept optional single letter suffix:

          1K = 1000, 1M = 1000000, ...

   iec    accept optional single letter suffix:

          1K = 1024, 1M = 1048576, ...

   iec-i  accept optional two-letter suffix:

          1Ki = 1024, 1Mi = 1048576, ...

FIELDS supports cut(1) style field ranges:
  N    N'th field, counted from 1
  N-   from N'th field, to end of line
  N-M  from N'th to M'th field (inclusive)
  -M   from first to M'th field (inclusive)
  -    all fields
Multiple fields/ranges can be separated with commas
";
const USAGE: &str = "{} [OPTION]... [NUMBER]...";

fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: &NumfmtOptions) -> UResult<()> {
    for l in args {
        match format_and_print(l, options) {
            Ok(_) => Ok(()),
            Err(e) => Err(NumfmtError::FormattingError(e.to_string())),
        }?;
    }

    Ok(())
}

fn handle_buffer<R>(input: R, options: &NumfmtOptions) -> UResult<()>
where
    R: BufRead,
{
    let mut lines = input.lines();
    for (idx, line) in lines.by_ref().enumerate() {
        match line {
            Ok(l) if idx < options.header => {
                println!("{}", l);
                Ok(())
            }
            Ok(l) => match format_and_print(&l, options) {
                Ok(_) => Ok(()),
                Err(e) => Err(NumfmtError::FormattingError(e.to_string())),
            },
            Err(e) => Err(NumfmtError::IoError(e.to_string())),
        }?;
    }
    Ok(())
}

fn parse_unit(s: &str) -> Result<Unit> {
    match s {
        "auto" => Ok(Unit::Auto),
        "si" => Ok(Unit::Si),
        "iec" => Ok(Unit::Iec(false)),
        "iec-i" => Ok(Unit::Iec(true)),
        "none" => Ok(Unit::None),
        _ => Err("Unsupported unit is specified".to_owned()),
    }
}

fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
    let from = parse_unit(args.value_of(options::FROM).unwrap())?;
    let to = parse_unit(args.value_of(options::TO).unwrap())?;

    let transform = TransformOptions { from, to };

    let padding = match args.value_of(options::PADDING) {
        Some(s) => s
            .parse::<isize>()
            .map_err(|_| s)
            .and_then(|n| match n {
                0 => Err(s),
                _ => Ok(n),
            })
            .map_err(|s| format!("invalid padding value {}", s.quote())),
        None => Ok(0),
    }?;

    let header = match args.occurrences_of(options::HEADER) {
        0 => Ok(0),
        _ => {
            let value = args.value_of(options::HEADER).unwrap();

            value
                .parse::<usize>()
                .map_err(|_| value)
                .and_then(|n| match n {
                    0 => Err(value),
                    _ => Ok(n),
                })
                .map_err(|value| format!("invalid header value {}", value.quote()))
        }
    }?;

    let fields = match args.value_of(options::FIELD).unwrap() {
        "-" => vec![Range {
            low: 1,
            high: std::usize::MAX,
        }],
        v => Range::from_list(v)?,
    };

    let delimiter = args.value_of(options::DELIMITER).map_or(Ok(None), |arg| {
        if arg.len() == 1 {
            Ok(Some(arg.to_string()))
        } else {
            Err("the delimiter must be a single character".to_string())
        }
    })?;

    // unwrap is fine because the argument has a default value
    let round = match args.value_of(options::ROUND).unwrap() {
        "up" => RoundMethod::Up,
        "down" => RoundMethod::Down,
        "from-zero" => RoundMethod::FromZero,
        "towards-zero" => RoundMethod::TowardsZero,
        "nearest" => RoundMethod::Nearest,
        _ => unreachable!("Should be restricted by clap"),
    };

    let suffix = args.value_of(options::SUFFIX).map(|s| s.to_owned());

    Ok(NumfmtOptions {
        transform,
        padding,
        header,
        fields,
        delimiter,
        round,
        suffix,
    })
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let options = parse_options(&matches).map_err(NumfmtError::IllegalArgument)?;

    let result = match matches.values_of(options::NUMBER) {
        Some(values) => handle_args(values, &options),
        None => {
            let stdin = std::io::stdin();
            let mut locked_stdin = stdin.lock();
            handle_buffer(&mut locked_stdin, &options)
        }
    };

    match result {
        Err(e) => {
            std::io::stdout().flush().expect("error flushing stdout");
            Err(e)
        }
        _ => Ok(()),
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .after_help(LONG_HELP)
        .override_usage(format_usage(USAGE))
        .allow_negative_numbers(true)
        .infer_long_args(true)
        .arg(
            Arg::new(options::DELIMITER)
                .short('d')
                .long(options::DELIMITER)
                .value_name("X")
                .help("use X instead of whitespace for field delimiter"),
        )
        .arg(
            Arg::new(options::FIELD)
                .long(options::FIELD)
                .help("replace the numbers in these input fields (default=1) see FIELDS below")
                .value_name("FIELDS")
                .default_value(options::FIELD_DEFAULT),
        )
        .arg(
            Arg::new(options::FROM)
                .long(options::FROM)
                .help("auto-scale input numbers to UNITs; see UNIT below")
                .value_name("UNIT")
                .default_value(options::FROM_DEFAULT),
        )
        .arg(
            Arg::new(options::TO)
                .long(options::TO)
                .help("auto-scale output numbers to UNITs; see UNIT below")
                .value_name("UNIT")
                .default_value(options::TO_DEFAULT),
        )
        .arg(
            Arg::new(options::PADDING)
                .long(options::PADDING)
                .help(
                    "pad the output to N characters; positive N will \
                     right-align; negative N will left-align; padding is \
                     ignored if the output is wider than N; the default is \
                     to automatically pad if a whitespace is found",
                )
                .value_name("N"),
        )
        .arg(
            Arg::new(options::HEADER)
                .long(options::HEADER)
                .help(
                    "print (without converting) the first N header lines; \
                     N defaults to 1 if not specified",
                )
                .value_name("N")
                .default_missing_value(options::HEADER_DEFAULT)
                .hide_default_value(true),
        )
        .arg(
            Arg::new(options::ROUND)
                .long(options::ROUND)
                .help(
                    "use METHOD for rounding when scaling; METHOD can be: up,\
                    down, from-zero (default), towards-zero, nearest",
                )
                .value_name("METHOD")
                .default_value("from-zero")
                .possible_values(&["up", "down", "from-zero", "towards-zero", "nearest"]),
        )
        .arg(
            Arg::new(options::SUFFIX)
                .long(options::SUFFIX)
                .help(
                    "print SUFFIX after each formatted number, and accept \
                    inputs optionally ending with SUFFIX",
                )
                .value_name("SUFFIX"),
        )
        .arg(
            Arg::new(options::NUMBER)
                .hide(true)
                .multiple_occurrences(true),
        )
}

#[cfg(test)]
mod tests {
    use super::{handle_buffer, NumfmtOptions, Range, RoundMethod, TransformOptions, Unit};
    use std::io::{BufReader, Error, ErrorKind, Read};
    struct MockBuffer {}

    impl Read for MockBuffer {
        fn read(&mut self, _: &mut [u8]) -> Result<usize, Error> {
            Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
        }
    }

    fn get_valid_options() -> NumfmtOptions {
        NumfmtOptions {
            transform: TransformOptions {
                from: Unit::None,
                to: Unit::None,
            },
            padding: 10,
            header: 1,
            fields: vec![Range { low: 0, high: 1 }],
            delimiter: None,
            round: RoundMethod::Nearest,
            suffix: None,
        }
    }

    #[test]
    fn broken_buffer_returns_io_error() {
        let mock_buffer = MockBuffer {};
        let result = handle_buffer(BufReader::new(mock_buffer), &get_valid_options())
            .expect_err("returned Ok after receiving IO error");
        let result_debug = format!("{:?}", result);
        let result_display = format!("{}", result);
        assert_eq!(result_debug, "IoError(\"broken pipe\")");
        assert_eq!(result_display, "broken pipe");
        assert_eq!(result.code(), 1);
    }

    #[test]
    fn non_numeric_returns_formatting_error() {
        let input_value = b"135\nhello";
        let result = handle_buffer(BufReader::new(&input_value[..]), &get_valid_options())
            .expect_err("returned Ok after receiving improperly formatted input");
        let result_debug = format!("{:?}", result);
        let result_display = format!("{}", result);
        assert_eq!(
            result_debug,
            "FormattingError(\"invalid suffix in input: 'hello'\")"
        );
        assert_eq!(result_display, "invalid suffix in input: 'hello'");
        assert_eq!(result.code(), 2);
    }

    #[test]
    fn valid_input_returns_ok() {
        let input_value = b"165\n100\n300\n500";
        let result = handle_buffer(BufReader::new(&input_value[..]), &get_valid_options());
        assert!(result.is_ok(), "did not return Ok for valid input");
    }
}
<commit_msg>numfmt: remove duplicate default hints from help<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Yury Krivopalov <ykrivopalov@yandex.ru>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore N'th M'th

use crate::errors::*;
use crate::format::format_and_print;
use crate::options::*;
use crate::units::{Result, Unit};
use clap::{crate_version, Arg, ArgMatches, Command};
use std::io::{BufRead, Write};
use uucore::display::Quotable;
use uucore::error::UResult;
use uucore::format_usage;
use uucore::ranges::Range;

pub mod errors;
pub mod format;
pub mod options;
mod units;

static ABOUT: &str = "Convert numbers from/to human-readable strings";
static LONG_HELP: &str = "UNIT options:
   none   no auto-scaling is done; suffixes will trigger an error

   auto   accept optional single/two letter suffix:

          1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,

   si     accept optional single letter suffix:

          1K = 1000, 1M = 1000000, ...

   iec    accept optional single letter suffix:

          1K = 1024, 1M = 1048576, ...

   iec-i  accept optional two-letter suffix:

          1Ki = 1024, 1Mi = 1048576, ...

FIELDS supports cut(1) style field ranges:
  N    N'th field, counted from 1
  N-   from N'th field, to end of line
  N-M  from N'th to M'th field (inclusive)
  -M   from first to M'th field (inclusive)
  -    all fields
Multiple fields/ranges can be separated with commas
";
const USAGE: &str = "{} [OPTION]... [NUMBER]...";

fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: &NumfmtOptions) -> UResult<()> {
    for l in args {
        match format_and_print(l, options) {
            Ok(_) => Ok(()),
            Err(e) => Err(NumfmtError::FormattingError(e.to_string())),
        }?;
    }

    Ok(())
}

fn handle_buffer<R>(input: R, options: &NumfmtOptions) -> UResult<()>
where
    R: BufRead,
{
    let mut lines = input.lines();
    for (idx, line) in lines.by_ref().enumerate() {
        match line {
            Ok(l) if idx < options.header => {
                println!("{}", l);
                Ok(())
            }
            Ok(l) => match format_and_print(&l, options) {
                Ok(_) => Ok(()),
                Err(e) => Err(NumfmtError::FormattingError(e.to_string())),
            },
            Err(e) => Err(NumfmtError::IoError(e.to_string())),
        }?;
    }
    Ok(())
}

fn parse_unit(s: &str) -> Result<Unit> {
    match s {
        "auto" => Ok(Unit::Auto),
        "si" => Ok(Unit::Si),
        "iec" => Ok(Unit::Iec(false)),
        "iec-i" => Ok(Unit::Iec(true)),
        "none" => Ok(Unit::None),
        _ => Err("Unsupported unit is specified".to_owned()),
    }
}

fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
    let from = parse_unit(args.value_of(options::FROM).unwrap())?;
    let to = parse_unit(args.value_of(options::TO).unwrap())?;

    let transform = TransformOptions { from, to };

    let padding = match args.value_of(options::PADDING) {
        Some(s) => s
            .parse::<isize>()
            .map_err(|_| s)
            .and_then(|n| match n {
                0 => Err(s),
                _ => Ok(n),
            })
            .map_err(|s| format!("invalid padding value {}", s.quote())),
        None => Ok(0),
    }?;

    let header = match args.occurrences_of(options::HEADER) {
        0 => Ok(0),
        _ => {
            let value = args.value_of(options::HEADER).unwrap();

            value
                .parse::<usize>()
                .map_err(|_| value)
                .and_then(|n| match n {
                    0 => Err(value),
                    _ => Ok(n),
                })
                .map_err(|value| format!("invalid header value {}", value.quote()))
        }
    }?;

    let fields = match args.value_of(options::FIELD).unwrap() {
        "-" => vec![Range {
            low: 1,
            high: std::usize::MAX,
        }],
        v => Range::from_list(v)?,
    };

    let delimiter = args.value_of(options::DELIMITER).map_or(Ok(None), |arg| {
        if arg.len() == 1 {
            Ok(Some(arg.to_string()))
        } else {
            Err("the delimiter must be a single character".to_string())
        }
    })?;

    // unwrap is fine because the argument has a default value
    let round = match args.value_of(options::ROUND).unwrap() {
        "up" => RoundMethod::Up,
        "down" => RoundMethod::Down,
        "from-zero" => RoundMethod::FromZero,
        "towards-zero" => RoundMethod::TowardsZero,
        "nearest" => RoundMethod::Nearest,
        _ => unreachable!("Should be restricted by clap"),
    };

    let suffix = args.value_of(options::SUFFIX).map(|s| s.to_owned());

    Ok(NumfmtOptions {
        transform,
        padding,
        header,
        fields,
        delimiter,
        round,
        suffix,
    })
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let options = parse_options(&matches).map_err(NumfmtError::IllegalArgument)?;

    let result = match matches.values_of(options::NUMBER) {
        Some(values) => handle_args(values, &options),
        None => {
            let stdin = std::io::stdin();
            let mut locked_stdin = stdin.lock();
            handle_buffer(&mut locked_stdin, &options)
        }
    };

    match result {
        Err(e) => {
            std::io::stdout().flush().expect("error flushing stdout");
            Err(e)
        }
        _ => Ok(()),
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .after_help(LONG_HELP)
        .override_usage(format_usage(USAGE))
        .allow_negative_numbers(true)
        .infer_long_args(true)
        .arg(
            Arg::new(options::DELIMITER)
                .short('d')
                .long(options::DELIMITER)
                .value_name("X")
                .help("use X instead of whitespace for field delimiter"),
        )
        .arg(
            Arg::new(options::FIELD)
                .long(options::FIELD)
                .help("replace the numbers in these input fields; see FIELDS below")
                .value_name("FIELDS")
                .default_value(options::FIELD_DEFAULT),
        )
        .arg(
            Arg::new(options::FROM)
                .long(options::FROM)
                .help("auto-scale input numbers to UNITs; see UNIT below")
                .value_name("UNIT")
                .default_value(options::FROM_DEFAULT),
        )
        .arg(
            Arg::new(options::TO)
                .long(options::TO)
                .help("auto-scale output numbers to UNITs; see UNIT below")
                .value_name("UNIT")
                .default_value(options::TO_DEFAULT),
        )
        .arg(
            Arg::new(options::PADDING)
                .long(options::PADDING)
                .help(
                    "pad the output to N characters; positive N will \
                     right-align; negative N will left-align; padding is \
                     ignored if the output is wider than N; the default is \
                     to automatically pad if a whitespace is found",
                )
                .value_name("N"),
        )
        .arg(
            Arg::new(options::HEADER)
                .long(options::HEADER)
                .help(
                    "print (without converting) the first N header lines; \
                     N defaults to 1 if not specified",
                )
                .value_name("N")
                .default_missing_value(options::HEADER_DEFAULT)
                .hide_default_value(true),
        )
        .arg(
            Arg::new(options::ROUND)
                .long(options::ROUND)
                .help(
                    "use METHOD for rounding when scaling; METHOD can be: up,\
                    down, from-zero, towards-zero, nearest",
                )
                .value_name("METHOD")
                .default_value("from-zero")
                .possible_values(&["up", "down", "from-zero", "towards-zero", "nearest"]),
        )
        .arg(
            Arg::new(options::SUFFIX)
                .long(options::SUFFIX)
                .help(
                    "print SUFFIX after each formatted number, and accept \
                    inputs optionally ending with SUFFIX",
                )
                .value_name("SUFFIX"),
        )
        .arg(
            Arg::new(options::NUMBER)
                .hide(true)
                .multiple_occurrences(true),
        )
}

#[cfg(test)]
mod tests {
    use super::{handle_buffer, NumfmtOptions, Range, RoundMethod, TransformOptions, Unit};
    use std::io::{BufReader, Error, ErrorKind, Read};
    struct MockBuffer {}

    impl Read for MockBuffer {
        fn read(&mut self, _: &mut [u8]) -> Result<usize, Error> {
            Err(Error::new(ErrorKind::BrokenPipe, "broken pipe"))
        }
    }

    fn get_valid_options() -> NumfmtOptions {
        NumfmtOptions {
            transform: TransformOptions {
                from: Unit::None,
                to: Unit::None,
            },
            padding: 10,
            header: 1,
            fields: vec![Range { low: 0, high: 1 }],
            delimiter: None,
            round: RoundMethod::Nearest,
            suffix: None,
        }
    }

    #[test]
    fn broken_buffer_returns_io_error() {
        let mock_buffer = MockBuffer {};
        let result = handle_buffer(BufReader::new(mock_buffer), &get_valid_options())
            .expect_err("returned Ok after receiving IO error");
        let result_debug = format!("{:?}", result);
        let result_display = format!("{}", result);
        assert_eq!(result_debug, "IoError(\"broken pipe\")");
        assert_eq!(result_display, "broken pipe");
        assert_eq!(result.code(), 1);
    }

    #[test]
    fn non_numeric_returns_formatting_error() {
        let input_value = b"135\nhello";
        let result = handle_buffer(BufReader::new(&input_value[..]), &get_valid_options())
            .expect_err("returned Ok after receiving improperly formatted input");
        let result_debug = format!("{:?}", result);
        let result_display = format!("{}", result);
        assert_eq!(
            result_debug,
            "FormattingError(\"invalid suffix in input: 'hello'\")"
        );
        assert_eq!(result_display, "invalid suffix in input: 'hello'");
        assert_eq!(result.code(), 2);
    }

    #[test]
    fn valid_input_returns_ok() {
        let input_value = b"165\n100\n300\n500";
        let result = handle_buffer(BufReader::new(&input_value[..]), &get_valid_options());
        assert!(result.is_ok(), "did not return Ok for valid input");
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0
#![allow(unused_macros)] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0

// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; MIT license

extern crate proc_macro;

//## rust proc-macro background info
//* ref: <https://dev.to/naufraghi/procedural-macro-in-rust-101-k3f> @@ <http://archive.is/Vbr5e>
//* ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ <http://archive.is/8YDua>

//## proc_dbg macro
//* used to help debug the compile-time proc_macro code

#[cfg(feature = "debug")]
macro_rules! proc_dbg {
    ($x:expr) => {
        dbg!($x)
    };
}
#[cfg(not(feature = "debug"))]
macro_rules! proc_dbg {
    ($x:expr) => {};
}

//## main!()

// main!( EXPR )
// generates a `main()` function for utilities within the uutils group
// EXPR == syn::Expr::Lit::String | syn::Expr::Path::Ident ~ EXPR contains the lexical path to the utility `uumain()` function
//* NOTE: EXPR is ultimately expected to be a multi-segment lexical path (eg, `crate::func`); so, if a single segment path is provided, a trailing "::uumain" is automatically added
//* for more generic use (and future use of "eager" macros), EXPR may be in either STRING or IDENT form

struct Tokens {
    expr: syn::Expr,
}

impl syn::parse::Parse for Tokens {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Tokens {
            expr: input.parse()?,
        })
    }
}

#[proc_macro]
#[cfg(not(test))] // work-around for GH:rust-lang/rust#62127; maint: can be removed when MinSRV >= v1.38.0
pub fn main(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let Tokens { expr } = syn::parse_macro_input!(stream as Tokens);
    proc_dbg!(&expr);

    const ARG_PANIC_TEXT: &str =
        "expected ident lexical path (or a literal string version) to 'uumain()' as argument";

    // match EXPR as a string literal or an ident path, o/w panic!()
    let mut expr = match expr {
        syn::Expr::Lit(expr_lit) => match expr_lit.lit {
            syn::Lit::Str(ref lit_str) => lit_str.parse::<syn::ExprPath>().unwrap(),
            _ => panic!("{}", ARG_PANIC_TEXT),
        },
        syn::Expr::Path(expr_path) => expr_path,
        _ => panic!("{}", ARG_PANIC_TEXT),
    };
    proc_dbg!(&expr);

    // for a single segment ExprPath argument, add trailing '::uumain' segment
    if expr.path.segments.len() < 2 {
        expr = syn::parse_quote!( #expr::uumain );
    };
    proc_dbg!(&expr);

    let f = quote::quote! { #expr(uucore::args_os()) };
    proc_dbg!(&f);

    // generate a uutils utility `main()` function, tailored for the calling utility
    let result = quote::quote! {
        fn main() {
            use std::io::Write;
            uucore::panic::mute_sigpipe_panic(); // suppress extraneous error output for SIGPIPE failures/panics
            let code = #f; // execute utility code
            std::io::stdout().flush().expect("could not flush stdout"); // (defensively) flush stdout for utility prior to exit; see <https://github.com/rust-lang/rust/issues/23818>
            std::process::exit(code);
        }
    };
    proc_macro::TokenStream::from(result)
}
<commit_msg>maint: remove obsolete attributes<commit_after>// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; MIT license

extern crate proc_macro;

//## rust proc-macro background info
//* ref: <https://dev.to/naufraghi/procedural-macro-in-rust-101-k3f> @@ <http://archive.is/Vbr5e>
//* ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ <http://archive.is/8YDua>

//## proc_dbg macro
//* used to help debug the compile-time proc_macro code

#[cfg(feature = "debug")]
macro_rules! proc_dbg {
    ($x:expr) => {
        dbg!($x)
    };
}
#[cfg(not(feature = "debug"))]
macro_rules! proc_dbg {
    ($x:expr) => {};
}

//## main!()

// main!( EXPR )
// generates a `main()` function for utilities within the uutils group
// EXPR == syn::Expr::Lit::String | syn::Expr::Path::Ident ~ EXPR contains the lexical path to the utility `uumain()` function
//* NOTE: EXPR is ultimately expected to be a multi-segment lexical path (eg, `crate::func`); so, if a single segment path is provided, a trailing "::uumain" is automatically added
//* for more generic use (and future use of "eager" macros), EXPR may be in either STRING or IDENT form

struct Tokens {
    expr: syn::Expr,
}

impl syn::parse::Parse for Tokens {
    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
        Ok(Tokens {
            expr: input.parse()?,
        })
    }
}

#[proc_macro]
pub fn main(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let Tokens { expr } = syn::parse_macro_input!(stream as Tokens);
    proc_dbg!(&expr);

    const ARG_PANIC_TEXT: &str =
        "expected ident lexical path (or a literal string version) to 'uumain()' as argument";

    // match EXPR as a string literal or an ident path, o/w panic!()
    let mut expr = match expr {
        syn::Expr::Lit(expr_lit) => match expr_lit.lit {
            syn::Lit::Str(ref lit_str) => lit_str.parse::<syn::ExprPath>().unwrap(),
            _ => panic!("{}", ARG_PANIC_TEXT),
        },
        syn::Expr::Path(expr_path) => expr_path,
        _ => panic!("{}", ARG_PANIC_TEXT),
    };
    proc_dbg!(&expr);

    // for a single segment ExprPath argument, add trailing '::uumain' segment
    if expr.path.segments.len() < 2 {
        expr = syn::parse_quote!( #expr::uumain );
    };
    proc_dbg!(&expr);

    let f = quote::quote! { #expr(uucore::args_os()) };
    proc_dbg!(&f);

    // generate a uutils utility `main()` function, tailored for the calling utility
    let result = quote::quote! {
        fn main() {
            use std::io::Write;
            uucore::panic::mute_sigpipe_panic(); // suppress extraneous error output for SIGPIPE failures/panics
            let code = #f; // execute utility code
            std::io::stdout().flush().expect("could not flush stdout"); // (defensively) flush stdout for utility prior to exit; see <https://github.com/rust-lang/rust/issues/23818>
            std::process::exit(code);
        }
    };
    proc_macro::TokenStream::from(result)
}
<|endoftext|>


<commit_before>use failure::Error;
use std::io;

pub fn read_line() -> io::Result<String> {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;

    // We trim the end of the buffer to remove the newline character
    Ok(buffer[..buffer.len() - 1].to_string())
}

pub fn read_usize_range(min: usize, max: usize) -> Result<usize, Error> {
    loop {
        let input = read_line()?.parse()?;

        if input >= min && input <= max {
            return Ok(input);
        } else {
            println!("input must be between {}-{}", min, max);
        }
    }
}

#[derive(Debug)]
pub enum Answer {
    Yes,
    No,
}

impl Into<bool> for Answer {
    fn into(self) -> bool {
        match self {
            Answer::Yes => true,
            Answer::No => false,
        }
    }
}

pub fn read_yn(default: Answer) -> io::Result<bool> {
    let line = read_line()?;

    let answer = match line.as_str() {
        "y" | "Y" => true,
        "n" | "N" => false,
        _ => default.into(),
    };

    Ok(answer)
}
<commit_msg>Fix broken command line input on Windows<commit_after>use failure::Error;
use std::io;

pub fn read_line() -> io::Result<String> {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer)?;

    // Trim the right side of the buffer to remove the newline character
    Ok(buffer.trim_right().to_string())
}

pub fn read_usize_range(min: usize, max: usize) -> Result<usize, Error> {
    loop {
        let input = read_line()?.parse()?;

        if input >= min && input <= max {
            return Ok(input);
        } else {
            println!("input must be between {}-{}", min, max);
        }
    }
}

#[derive(Debug)]
pub enum Answer {
    Yes,
    No,
}

impl Into<bool> for Answer {
    fn into(self) -> bool {
        match self {
            Answer::Yes => true,
            Answer::No => false,
        }
    }
}

pub fn read_yn(default: Answer) -> io::Result<bool> {
    let line = read_line()?;

    let answer = match line.as_str() {
        "y" | "Y" => true,
        "n" | "N" => false,
        _ => default.into(),
    };

    Ok(answer)
}
<|endoftext|>


<commit_before>// Learning.

use term::Term;
use stroke::Stroke;
use timelearn::{Problem, Store};

use std::io::Write;
use termion::color;

pub struct Learn {
    store: Store,
    term: Term,
}

impl Learn {
    pub fn new(store: Store, term: Term) -> Learn {
        Learn {
            store: store,
            term: term,
        }
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.store.get_next().unwrap() {
                None => {
                    match self.store.get_new().unwrap() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            match status {
                Status::Stopped => break,
                Status::Continue(factor) => self.store.update(word, factor).unwrap(),
            }
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &Problem) -> Status {
        let counts = self.store.get_counts().unwrap();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval)).unwrap();
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
        }
        writeln!(self.term, "\r").unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w Problem,
    strokes: Vec<Stroke>,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww Problem) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            strokes: Stroke::parse_strokes(&word.answer).unwrap(),
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.question,
               if self.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user, &self.strokes)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.strokes, &self.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let result;
        loop {
            self.prompt();
            if self.strokes == self.user {
                result = Status::Continue(if self.errors > 0 { 1 } else { 4 });
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.strokes.len() ||
                    self.user[pos-1] != self.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        match result {
            Status::Continue(_) => {
                writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
            }
            Status::Stopped => writeln!(self.term, "\r").unwrap(),
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke], expected: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for (i, st) in strokes.iter().enumerate() {
        if !first {
            buf.push(b'/');
        }
        first = false;

        let correct = expected.get(i) == Some(st);
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::LightRed),
                   color::Fg(color::Black)).unwrap();
        }
        write!(&mut buf, "{}", st).unwrap();
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::Reset),
                   color::Fg(color::Reset)).unwrap();
        }
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    Continue(u8),
    Stopped,
}
<commit_msg>Add an 'active' counter<commit_after>// Learning.

use term::Term;
use stroke::Stroke;
use timelearn::{Problem, Store};

use std::io::Write;
use termion::color;

pub struct Learn {
    store: Store,
    term: Term,
}

impl Learn {
    pub fn new(store: Store, term: Term) -> Learn {
        Learn {
            store: store,
            term: term,
        }
    }

    pub fn run(&mut self) {
        loop {
            // TODO: Check for things that have expired we need to learn.

            let mut word = match self.store.get_next().unwrap() {
                None => {
                    match self.store.get_new().unwrap() {
                        None => {
                            println!("No more words to learn\r");
                            return;
                        },
                        Some(word) => word,
                    }
                }
                Some(word) => word,
            };

            let status = self.single(&mut word);

            match status {
                Status::Stopped => break,
                Status::Continue(factor) => self.store.update(word, factor).unwrap(),
            }
        }
    }

    // Learn a single word, updating its timing information based on how well it was learned.
    fn single(&mut self, word: &Problem) -> Status {
        let counts = self.store.get_counts().unwrap();

        writeln!(self.term, "\r\nActive: {}, Later: {}, Unlearned: {}, Interval {}\r",
                 counts.active, counts.later, counts.unlearned,
                 humanize_time(word.interval)).unwrap();
        let mut active = 0;
        for b in &counts.buckets {
            writeln!(self.term, "  {:-4}: {:4} {}\r", b.name, b.count,
                     stars(65, b.count, counts.active + counts.later)).unwrap();
            // TODO: This shouldn't be done by string matching, it is fragile.
            if b.name != "day" && b.name != "mon" {
                active += b.count;
            }
        }
        writeln!(self.term, "  active: {}\r\n\r", active).unwrap();
        self.term.flush().unwrap();

        let mut state = Single::new(&mut self.term, word);
        state.run()
    }
}

// Format an interval (in seconds) in terms of nicer units.
fn humanize_time(interval: f64) -> String {
    let mut val = interval;
    for unit in UNITS {
        if val < unit.div {
            return format!("{:.1} {}", val, unit.name);
        }
        val /= unit.div;
    }
    // Out of bounds, return the unmodified time.
    format!("{:.1} seconds", interval)
}

struct UnitEntry {
    name: &'static str,
    div: f64,
}

static UNITS: &'static [UnitEntry] = &[
    UnitEntry{ name: "seconds", div: 60.0 },
    UnitEntry{ name: "minutes", div: 60.0 },
    UnitEntry{ name: "hours", div: 24.0 },
    UnitEntry{ name: "days", div: 365.0 },
    UnitEntry{ name: "months", div: 12.0 },
    UnitEntry{ name: "years", div: 1.0e6 },
];

// Print a line of stars resembling a histogram bar.  `len` is the number of stars to use, a is the
// number in question, and total is the expected total.
fn stars(len: usize, value: usize, total: usize) -> String {
    let mut buf = String::new();
    buf.push('|');
    let thresh = value as f64 / total as f64 * len as f64;
    for i in 0 .. len {
        if (i as f64) < thresh {
            buf.push('*');
        } else {
            buf.push(' ');
        };
    }
    buf.push('|');
    buf
}

struct Single<'t, 'w> {
    term: &'t mut Term,
    word: &'w Problem,
    strokes: Vec<Stroke>,
    user: Vec<Stroke>,
    errors: u32,
}

impl<'t, 'w> Single<'t, 'w> {
    fn new<'tt, 'ww>(term: &'tt mut Term, word: &'ww Problem) -> Single<'tt, 'ww> {
        Single {
            term: term,
            word: word,
            strokes: Stroke::parse_strokes(&word.answer).unwrap(),
            user: vec![],
            errors: 0,
        }
    }

    fn prompt(&mut self) {
        write!(self.term, "\r\x1b[J{:20}: {}{}",
               self.word.question,
               if self.strokes == self.user {
                   if self.errors == 0 { '✓' } else { '✗' }
               } else { ' ' },
               slashed(&self.user, &self.strokes)).unwrap();
        if self.errors > 0 {
            write!(self.term, "  ({})", slashed(&self.strokes, &self.strokes)).unwrap();
        }
        self.term.flush().unwrap();
    }

    fn run(&mut self) -> Status {
        let result;
        loop {
            self.prompt();
            if self.strokes == self.user {
                result = Status::Continue(if self.errors > 0 { 1 } else { 4 });
                break;
            }

            let stroke = match self.term.read_stroke().unwrap() {
                None => { result = Status::Stopped; break; }
                Some(st) => st,
            };
            if stroke.is_star() {
                self.user.pop();
            } else {
                self.user.push(stroke);
                let pos = self.user.len();
                if pos > self.strokes.len() ||
                    self.user[pos-1] != self.strokes[pos-1]
                {
                    self.errors += 1;
                }
            }
        }

        match result {
            Status::Continue(_) => {
                writeln!(self.term, "\r\nNew interval {}\r", humanize_time(self.word.interval)).unwrap();
            }
            Status::Stopped => writeln!(self.term, "\r").unwrap(),
        }
        self.term.flush().unwrap();
        result
    }
}

// Generate a slash separated version of the given stroke list.
fn slashed(strokes: &[Stroke], expected: &[Stroke]) -> String {
    let mut buf = vec![];
    let mut first = true;

    for (i, st) in strokes.iter().enumerate() {
        if !first {
            buf.push(b'/');
        }
        first = false;

        let correct = expected.get(i) == Some(st);
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::LightRed),
                   color::Fg(color::Black)).unwrap();
        }
        write!(&mut buf, "{}", st).unwrap();
        if !correct {
            write!(&mut buf, "{}{}",
                   color::Bg(color::Reset),
                   color::Fg(color::Reset)).unwrap();
        }
    }
    String::from_utf8(buf).unwrap()
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum Status {
    Continue(u8),
    Stopped,
}
<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        unimplemented!();
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        let x = coord.x + 2;
        let y = coord.y + 2;
        &self.board[x as usize][y as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        unimplemented!();
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return an array of Options instead of a Vec so that get_hex_field_neighbors and
    // is_hex_removable know which neighbors are on which side of the hex. They need to know this
    // for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable if it is attached to the board by 3 or less
    //                       *adjacent* sides
    fn get_neighbors(&self) -> [Option<HexCoord>; 6] {
        let mut neighbors = [None; 6];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors[0] = Some(HexCoord::new(self.x, self.y + 1));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors[1] = Some(HexCoord::new(self.x + 1, self.y));
        }
        if self.x < 2 && self.y > -2 {
            neighbors[2] = Some(HexCoord::new(self.x + 1, self.y - 1));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors[3] = Some(HexCoord::new(self.x, self.y - 1));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors[4] = Some(HexCoord::new(self.x - 1, self.y));
        }
        if self.x > -2 && self.y < 2 {
            neighbors[5] = Some(HexCoord::new(self.x - 1, self.y + 1));
        }

        neighbors
    }
}
<commit_msg>Implement get_hex_neighbors<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        unimplemented!();
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        let x = coord.x + 2;
        let y = coord.y + 2;
        &self.board[x as usize][y as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter(|&&c| match c {
                Some(_) => true,
                None => false,
            })
            .map(|c| c.unwrap())
            .filter(|c| match *self.get_hex(c) {
                Some(_) => true,
                None => false,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return an array of Options instead of a Vec so that get_hex_field_neighbors and
    // is_hex_removable know which neighbors are on which side of the hex. They need to know this
    // for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable if it is attached to the board by 3 or less
    //                       *adjacent* sides
    fn get_neighbors(&self) -> [Option<HexCoord>; 6] {
        let mut neighbors = [None; 6];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors[0] = Some(HexCoord::new(self.x, self.y + 1));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors[1] = Some(HexCoord::new(self.x + 1, self.y));
        }
        if self.x < 2 && self.y > -2 {
            neighbors[2] = Some(HexCoord::new(self.x + 1, self.y - 1));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors[3] = Some(HexCoord::new(self.x, self.y - 1));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors[4] = Some(HexCoord::new(self.x - 1, self.y));
        }
        if self.x > -2 && self.y < 2 {
            neighbors[5] = Some(HexCoord::new(self.x - 1, self.y + 1));
        }

        neighbors
    }
}
<|endoftext|>


<commit_before>use http::server::request::{AbsolutePath};
use regex::Regex;

use iron::{Middleware, Request, Response, Alloy, Chain};
use iron::middleware::{Status, Continue};

/// `Mount` is a simple mounting middleware.
///
/// `Mount` allows you to mount other middleware within a larger chain.
///
/// Mounted middleware will receive a modified version of the request
/// url with the mount pattern removed from the start of the url.
pub struct Mount {
    route: String,
    matches: Regex,
    middleware: Box<Middleware + Send>
}

impl Clone for Mount {
    fn clone(&self) -> Mount {
        Mount {
            route: self.route.clone(),
            matches: self.matches.clone(),
            middleware: self.middleware.clone_box()
        }
    }
}

impl Mount {
    /// Creates a new instance of `Mount` mounting the given instance of Iron
    /// on the given path.
    pub fn new<M: Middleware + Send>(route: &str, middleware: M) -> Mount {
        Mount {
            route: route.to_string(),
            middleware: box middleware,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

impl Middleware for Mount {
    fn enter(&mut self,
             req: &mut Request,
             res: &mut Response,
             alloy: &mut Alloy) -> Status {
        // This method is ugly, but it is hard to make it pretty
        // because we can't both borrow path from inside of request
        // while allowing chain.dispatch to borrow it as mutable.

        match req.request_uri {
           AbsolutePath(ref path) => {
               // Short circuit if we don't match.
                if !self.matches.is_match(path.as_slice()) {
                    return Continue;
                }
           },
           // Short circuit if this is not an AbsolutePath.
           _ => { return Continue; }
        }

        // We are a match, so fire off to our child instance.
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = path.as_slice().slice_from(self.route.len()).to_string();
            },
            // Absolutely cannot happen because of our previous check,
            // but this is here just to be careful.
            _ => { return Continue; }
        } // Previous borrow of req ends here.

        // So we can borrow it again here.
        let terminator = self.middleware.enter(req, res, alloy);
        let _ = self.middleware.exit(req, res, alloy);

        // And repair the damage here, for future middleware
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = self.route.clone().append(path.as_slice());
            },
            // This really, really should never happen.
            _ => { fail!("The impossible happened."); }
        }

        // We dispatched the request, so return the terminator.
        terminator
    }
}

<commit_msg>(fix) Special cases empty routes to be "/" instead of ""<commit_after>use http::server::request::{AbsolutePath};
use regex::Regex;

use iron::{Middleware, Request, Response, Alloy, Chain};
use iron::middleware::{Status, Continue};

/// `Mount` is a simple mounting middleware.
///
/// `Mount` allows you to mount other middleware within a larger chain.
///
/// Mounted middleware will receive a modified version of the request
/// url with the mount pattern removed from the start of the url.
pub struct Mount {
    route: String,
    matches: Regex,
    middleware: Box<Middleware + Send>
}

impl Clone for Mount {
    fn clone(&self) -> Mount {
        Mount {
            route: self.route.clone(),
            matches: self.matches.clone(),
            middleware: self.middleware.clone_box()
        }
    }
}

impl Mount {
    /// Creates a new instance of `Mount` mounting the given instance of Iron
    /// on the given path.
    pub fn new<M: Middleware + Send>(route: &str, middleware: M) -> Mount {
        Mount {
            route: route.to_string(),
            middleware: box middleware,
            matches: to_regex(route)
        }
    }
}

fn to_regex(route: &str) -> Regex {
    Regex::new("^".to_string().append(route).as_slice()).unwrap()
}

impl Middleware for Mount {
    fn enter(&mut self,
             req: &mut Request,
             res: &mut Response,
             alloy: &mut Alloy) -> Status {
        // This method is ugly, but it is hard to make it pretty
        // because we can't both borrow path from inside of request
        // while allowing chain.dispatch to borrow it as mutable.

        match req.request_uri {
           AbsolutePath(ref path) => {
               // Short circuit if we don't match.
                if !self.matches.is_match(path.as_slice()) {
                    return Continue;
                }
           },
           // Short circuit if this is not an AbsolutePath.
           _ => { return Continue; }
        }

        // We are a match, so fire off to our child instance.
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = path.as_slice().slice_from(self.route.len()).to_string();
                if path.is_empty() {
                    *path = "/".to_string();
                }
            },
            // Absolutely cannot happen because of our previous check,
            // but this is here just to be careful.
            _ => { return Continue; }
        } // Previous borrow of req ends here.

        // So we can borrow it again here.
        let terminator = self.middleware.enter(req, res, alloy);
        let _ = self.middleware.exit(req, res, alloy);

        // And repair the damage here, for future middleware
        match req.request_uri {
            AbsolutePath(ref mut path) => {
                *path = self.route.clone().append(path.as_slice());
            },
            // This really, really should never happen.
            _ => { fail!("The impossible happened."); }
        }

        // We dispatched the request, so return the terminator.
        terminator
    }
}

<|endoftext|>


<commit_before>use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// This type provides MUTual EXclusion based on spinning.
///
/// # Description
///
/// This structure behaves a lot like a normal Mutex. There are some differences:
///
/// - It may be used outside the runtime.
///   - A normal mutex will fail when used without the runtime, this will just lock
///   - When the runtime is present, it will call the deschedule function when appropriate
/// - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
///
/// When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
/// helpful. In other cases however, you are encouraged to use the locks from the standard
/// library.
///
/// # Simple example
///
/// ```
/// use spin;
/// let spin_mutex = spin::Mutex::new(0);
///
/// // Modify the data
/// {
///     let mut data = spin_mutex.lock();
///     *data = 2;
/// }
///
/// // Read the data
/// let answer =
/// {
///     let data = spin_mutex.lock();
///     *data
/// };
///
/// assert_eq!(answer, 2);
/// ```
///
/// # Thread-safety example
///
/// ```
/// use spin;
/// use std::sync::{Arc, Barrier};
///
/// let numthreads = 1000;
/// let spin_mutex = Arc::new(spin::Mutex::new(0));
///
/// // We use a barrier to ensure the readout happens after all writing
/// let barrier = Arc::new(Barrier::new(numthreads + 1));
///
/// for _ in (0..numthreads)
/// {
///     let my_barrier = barrier.clone();
///     let my_lock = spin_mutex.clone();
///     std::thread::Thread::spawn(move||
///     {
///         let mut guard = my_lock.lock();
///         *guard += 1;
///
///         // Release the lock to prevent a deadlock
///         drop(guard);
///         my_barrier.wait();
///     });
/// }
///
/// barrier.wait();
///
/// let answer = { *spin_mutex.lock() };
/// assert_eq!(answer, numthreads);
/// ```
pub struct Mutex<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Mutex<T> {}

/// A Mutex which may be used statically.
///
/// ```
/// use spin::{self, STATIC_MUTEX_INIT};
///
/// static SPLCK: spin::StaticMutex = STATIC_MUTEX_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticMutex = Mutex<()>;

/// A initializer for StaticMutex, containing no data.
pub const STATIC_MUTEX_INIT: StaticMutex = Mutex {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

impl<T> Mutex<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Mutex<T>
    {
        Mutex
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    ///     // The lock is implicitly dropped
    /// }
    ///
    /// ```
    pub fn lock(&self) -> MutexGuard<T>
    {
        self.obtain_lock();
        MutexGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for MutexGuard<'a, T>
{
    /// The dropping of the MutexGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<commit_msg>Fix test<commit_after>use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// This type provides MUTual EXclusion based on spinning.
///
/// # Description
///
/// This structure behaves a lot like a normal Mutex. There are some differences:
///
/// - It may be used outside the runtime.
///   - A normal mutex will fail when used without the runtime, this will just lock
///   - When the runtime is present, it will call the deschedule function when appropriate
/// - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
///
/// When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
/// helpful. In other cases however, you are encouraged to use the locks from the standard
/// library.
///
/// # Simple example
///
/// ```
/// use spin;
/// let spin_mutex = spin::Mutex::new(0);
///
/// // Modify the data
/// {
///     let mut data = spin_mutex.lock();
///     *data = 2;
/// }
///
/// // Read the data
/// let answer =
/// {
///     let data = spin_mutex.lock();
///     *data
/// };
///
/// assert_eq!(answer, 2);
/// ```
///
/// # Thread-safety example
///
/// ```
/// use spin;
/// use std::sync::{Arc, Barrier};
///
/// let numthreads = 1000;
/// let spin_mutex = Arc::new(spin::Mutex::new(0));
///
/// // We use a barrier to ensure the readout happens after all writing
/// let barrier = Arc::new(Barrier::new(numthreads + 1));
///
/// for _ in (0..numthreads)
/// {
///     let my_barrier = barrier.clone();
///     let my_lock = spin_mutex.clone();
///     std::thread::spawn(move||
///     {
///         let mut guard = my_lock.lock();
///         *guard += 1;
///
///         // Release the lock to prevent a deadlock
///         drop(guard);
///         my_barrier.wait();
///     });
/// }
///
/// barrier.wait();
///
/// let answer = { *spin_mutex.lock() };
/// assert_eq!(answer, numthreads);
/// ```
pub struct Mutex<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
pub struct MutexGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Mutex<T> {}

/// A Mutex which may be used statically.
///
/// ```
/// use spin::{self, STATIC_MUTEX_INIT};
///
/// static SPLCK: spin::StaticMutex = STATIC_MUTEX_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticMutex = Mutex<()>;

/// A initializer for StaticMutex, containing no data.
pub const STATIC_MUTEX_INIT: StaticMutex = Mutex {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

impl<T> Mutex<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    pub fn new(user_data: T) -> Mutex<T>
    {
        Mutex
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spin::Mutex::new(0);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    ///     // The lock is implicitly dropped
    /// }
    ///
    /// ```
    pub fn lock(&self) -> MutexGuard<T>
    {
        self.obtain_lock();
        MutexGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for MutexGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for MutexGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for MutexGuard<'a, T>
{
    /// The dropping of the MutexGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>