linya 0.3.0

Simple concurrent progress bars.
Documentation
# linya

[![Workflow Status](https://github.com/fosskers/linya/workflows/Tests/badge.svg)](https://github.com/fosskers/linya/actions?query=workflow%3A%22Tests%22)
[![](https://img.shields.io/crates/v/linya.svg)](https://crates.io/crates/linya)

Simple concurrent progress bars.

![](https://github.com/fosskers/linya/blob/master/screenshots/multi.gif?raw=true)

## Features

- Intuitive API.
- First-class support for `rayon`, etc.
- Efficient, allocation-free redraws.
- Addition of new subbars on-the-fly.
- Single-threaded multi-bars.
- Light-weight, only a single dependency.

## Usage

`linya` is designed around the multi-bar case, and unlike other progress bar
libraries, has no separate type for individual bars. Instead, we use the
`Progress` type, a "bar coordinator".

### Multi Bars

To mutably access a `Progress` across threads it must be wrapped in the
usual [concurrent sharing types][arcmutex]. With `rayon` specifically, only
`Mutex` is necessary:

```rust
use std::sync::Mutex;
use linya::{Bar, Progress};
use rayon::prelude::*;

let progress = Mutex::new(Progress::new());

// `into_par_iter()` is from `rayon`, and lets us parallelize some
// operation over a collection "for free".
(0..10).into_par_iter().for_each(|n| {
  let bar: Bar = progress.lock().unwrap().bar(50, format!("Downloading {}", n));

  // ... Your logic ...

  // Increment the bar and draw it immediately.
  // This is likely called in some inner loop or other closure.
  progress.lock().unwrap().inc_and_draw(&bar, 10);
});
```

Notice that new bars are added on-the-fly from within forked threads. We
call `Progress::bar` to obtain a new "bar handle", and then pass that
handle back to the parent `Progress` when incrementing/drawing.

See `Progress::inc_and_draw` and `Progress::set_and_draw` to advance and
render the bars.

### Single Bars

`Progress` can also be used in a single-threaded context for individual
bars. The usage is the same, except that no locking is required:

```rust
use linya::{Bar, Progress};

let mut progress = Progress::new();
let bar: Bar = progress.bar(50, "Downloading");

// Use in a loop, etc.
progress.set_and_draw(&bar, 10);
```

In this way, you could even have multi-bars in a single-threaded context.

## Caveats

Some of the points below may be fixed in future releases.

- Your terminal must support ANSI codes.
- No dedicated render thread, to keep usage simple.
- No bar templating, to avoid dependencies.
- No other bar styling ([yet]).
- No "rates", since rerenders are not time-based.
- No bar clearing after completion.
- No spinners, also due to no sense of time.
- No dynamic resizing of bars if window size changes.

If you need more customizable progress bars and are willing to accept
heavier dependencies, please consider [indicatif].

Note also that using more than one `Progress` at the same time leads to
unspecified behaviour.

## Trivia

_Linya_ is the Quenya word for "pool", as in a [beautiful mountain pool][mirrormere].

[mirrormere]: https://www.tednasmith.com/tolkien/durins-crown-and-the-mirrormere/
[arcmutex]: https://doc.rust-lang.org/stable/book/ch16-03-shared-state.html?#atomic-reference-counting-with-arct
[yet]: https://internals.rust-lang.org/t/fmt-dynamic-fill-character/13609
[indicatif]: https://lib.rs/crates/indicatif