numfmt 1.1.1

Fast and friendly Rust number formatting
Documentation
Fast and friendly Rust number formatting.

# Format numbers.

Provides a [`Formatter`] to format decimal numbers with various methods. Formatting is
performance focused, it is generally faster than `std` with more features. There is also a
[string parser](#parsing) which can use a string to define a [`Formatter`] following a specific
grammar.

# Procedure
Formatting is done through the [`Formatter::fmt`] which follows the procedure:
1. Scale the number with the defined [`Scales`],
2. Check if _scaled number_ is above or below the [scientific notation
   cutoffs](#scientific-notation),
3. Add defined thousands separator,
4. Stop at defined [`Precision`],
5. Applies valid prefix, suffix, and unit decorations.

# Usage
## Default use
[`Default::default`] provides a general use default formatter with the following properties:
- [`Scales::short`] scaling,
- `,` thousands separator,
- 3 decimal places

```rust
# use numfmt::*;
let mut f = Formatter::default();
assert_eq!(f.fmt(0.0), "0");
assert_eq!(f.fmt(12345.6789), "12.345 K");
assert_eq!(f.fmt(0.00012345), "1.234e-4");
assert_eq!(f.fmt(123456e22), "1,234.559 Y");
```

## Custom use
The [`Formatter`] has many different options to customise how the number should be formatted.
The example below shows how a currency format would be developed:
```rust
# use numfmt::*;
let mut f = Formatter::new() // start with blank representation
    .separator(',').unwrap()
    .prefix("AU$").unwrap()
    .precision(Precision::Decimals(2));

assert_eq!(f.fmt(0.52), "AU$0.52");
assert_eq!(f.fmt(1234.567), "AU$1,234.56");
assert_eq!(f.fmt(12345678900.0), "AU$12,345,678,900.0");
```

# Scientific Notation
Scientific notation kicks in when the scaled number is greater than 12 integer digits
(123,456,789,000) or less than 3 leading zeros (0.0001234). The number _always_ has a leading
integer digit and has a default of **7 significant figures**.

# Precision
Precision, either with number of decimals or significant figures can be specified with
[`Precision`].
```rust
# use numfmt::*;
let mut f = Formatter::new();
assert_eq!(f.fmt(1234.56789), "1234.56789");

f = f.precision(Precision::Decimals(2));
assert_eq!(f.fmt(1234.56789), "1234.56");

f = f.precision(Precision::Significance(5));
assert_eq!(f.fmt(1234.56789), "1234.5");
```

# Performance
Formatting is generally faster than `std`'s `f64::to_string` implementation. When constructing
a [`Formatter`] there is an allocation for the buffer, and an allocation for any scales.
Reusing a [`Formatter`] is recommended to avoid unnecessary allocations. The `cached` row shows
the better performance reusing a formatter.

| Time (ns)        | 0.0 | 0.1234 | 2.718281828459045 | 1.797693148623157e307 |
| ---------------- | --- | ------ | ----------------- | --------------------- |
| numfmt - default | 35  | 115    | 153               | 195                   |
| numfmt - cached  | 2   | 75     | 89                | 126                   |
| std              | 35  | 96     | 105               | 214                   |

# Example - File size formatter
Using a combination of a scale, suffix, and precision, a file size printer can be constructed:
```rust
# use numfmt::*;
let mut f = Formatter::new()
                .scales(Scales::binary())
                .precision(Precision::Significance(3))
                .suffix("B").unwrap();

assert_eq!(f.fmt(123_f64), "123 B");
assert_eq!(f.fmt(1234_f64), "1.20 kiB");
assert_eq!(f.fmt(1_048_576_f64), "1.0 MiB");
assert_eq!(f.fmt(123456789876543_f64), "112 TiB");
```

# Parsing
A grammar is defined that can parse into a [`Formatter`]. This string representation can be
used as a user input for formatting numbers. The grammar is defined by a _prefix_, the number
format enclosed in brackets, and then the _suffix_.
```text
prefix[[.#|~#|.*][%|s|b|n][/<char>]]suffix
^----^ ^--------^^-------^^-------^ ^----^
prefix precision scale    separator suffix
```
> Each component is optional, including the number format. All formats are applied to the
_default_ [`Formatter`] so an empty format results in the default _formatter_.

## Prefix and Suffix
The prefix and suffix are bound to the supported lengths, and can have any character in them.
To use `[]` characters, a double bracket must be used.

### Example
```rust
# use numfmt::*;
let mut f: Formatter;
f = "".parse().unwrap();
assert_eq!(f.fmt(1.234), "1.234");

f = "prefix ".parse().unwrap();
assert_eq!(f.fmt(1.234), "prefix 1.234");

f = "[] suffix".parse().unwrap();
assert_eq!(f.fmt(1.234), "1.234 suffix");

f = "[[prefix [] suffix]]".parse().unwrap();
assert_eq!(f.fmt(1.234), "[prefix 1.234 suffix]");
```

## Precision
Precision is defined using a `.` for decimals, or a `~` for significant figures, followed by
a number. A maximum of 255 is supported. There is a special case: `.*` which removes any
default precision and uses [`Precision::Unspecified`].

### Example
```rust
# use numfmt::*;
let mut f: Formatter;
f = "[.2]".parse().unwrap(); // use two decimal places
assert_eq!(f.fmt(1.2345), "1.23");

f = "[.0]".parse().unwrap(); // use zero decimal places
assert_eq!(f.fmt(10.234), "10");

f = "[.*]".parse().unwrap(); // arbitary precision
assert_eq!(f.fmt(1.234), "1.234");
assert_eq!(f.fmt(12.2), "12.2");

f = "[~3]".parse().unwrap(); // 3 significant figures
assert_eq!(f.fmt(1.234), "1.23");
assert_eq!(f.fmt(10.234), "10.2");
```

## Scale
Scale uses a character to denote what scaling should be used. By default the SI scaling is
used. The following characters are supported:
- `s` for SI scaling ([`Scales::short`]),
- `%` for percentage scaling ([`Formatter::percentage`]),
- `m` for metric scaling ([`Scales::metric`]),
- `b` for binary scaling ([`Scales::binary`]),
- `n` for no scaling ([`Scales::none`])

### Example
```rust
# use numfmt::*;
let mut f: Formatter;
f = "".parse().unwrap(); // default si scaling used
assert_eq!(f.fmt(12345.0), "12.345 K");

f = "[n]".parse().unwrap(); // turn off scaling
assert_eq!(f.fmt(12345.0), "12,345.0");

f = "[%.2]".parse().unwrap(); // format as percentages with 2 decimal places
assert_eq!(f.fmt(0.234), "23.40%");

f = "[b]".parse().unwrap(); // use a binary scaler
assert_eq!(f.fmt(3.14 * 1024.0 * 1024.0), "3.14 Mi");
```

## Separator
A separator character can be specified by using a forward slash `/` followed by a character.
The parser uses the _next character verbatim_, unless that character is `]` in which case the
separator is set to `None`. The default separator is a comma.

### Example
```rust
# use numfmt::*;
let mut f: Formatter;
f = "[n]".parse().unwrap(); // turn off scaling to see separator
assert_eq!(f.fmt(12345.0), "12,345.0");

f = "[n/]".parse().unwrap(); // use no separator
assert_eq!(f.fmt(12345.0), "12345.0");

f = "[n/.]".parse().unwrap(); // use a period
assert_eq!(f.fmt(12345.0), "12.345.0");

f = "[n/_]".parse().unwrap(); // use a underscroll
assert_eq!(f.fmt(12345.0), "12_345.0");

f = "[n/ ]".parse().unwrap(); // use a space
assert_eq!(f.fmt(12345.0), "12 345.0");
```

## Composing formats
There have been examples of composing formats already. The `prefix[num]suffix` order must be
adhered to, but the ordering within the number format is arbitary. It is recommended to keep it
consistent with _precison, scaling, separator_ as this assists with readability and lowers the
risk of malformed formats (which will error on the parsing phase).

### Various composed examples
```rust
# use numfmt::*;
let mut f: Formatter;

// Percentages to two decimal places
f = "[.2%]".parse().unwrap();
assert_eq!(f.fmt(0.012345), "1.23%");

// Currency to zero decimal places
// notice the `n` for no scaling
f = "$[.0n] USD".parse().unwrap();
assert_eq!(f.fmt(123_456_789.12345), "$123,456,789 USD");

// Formatting file sizes
f = "[~3b]B".parse().unwrap();
assert_eq!(f.fmt(123_456_789.0), "117 MiB");

// Units to 1 decimal place
f = "[.1n] m/s".parse().unwrap();
assert_eq!(f.fmt(12345.68), "12,345.6 m/s");
```