inkling/lib.rs
1//! # inkling
2//!
3//! Reveal arbitrary ASCII art as a progress indicator.
4//!
5//! A normal progress bar maps a scalar `0..=1` onto *how much of a line is
6//! filled*. `inkling` generalises that to two dimensions: it maps progress onto
7//! **the order in which the glyphs of a picture appear**. Give it a dragon and it
8//! paints the dragon as your task runs.
9//!
10//! ## Quick start
11//!
12//! The easy front door is [`Loader`](loader::Loader): make one with a total,
13//! advance it from anywhere, and a living reveal paints itself until you finish.
14//!
15//! ```no_run
16//! use inkling::Loader;
17//!
18//! let loader = Loader::new(100);
19//! for _ in 0..100 {
20//! // ... a slice of work ...
21//! loader.inc(1);
22//! }
23//! loader.finish();
24//! ```
25//!
26//! Or wrap any iterator and forget about it:
27//!
28//! ```no_run
29//! use inkling::ProgressIteratorExt;
30//!
31//! for _item in (0..100).inkling() {
32//! // ... work ...
33//! }
34//! ```
35//!
36//! ## The one idea
37//!
38//! Everything turns on a single abstraction, the [`RankMap`]: every *ink* cell of
39//! the art is assigned a **reveal rank** in `0..=1`, and a cell is visible exactly
40//! when `rank <= progress`. Because rank is fixed and monotonic, the reveal can
41//! never run backwards, any progress value renders directly (it is seekable and
42//! resumable), and the whole thing is pure.
43//!
44//! *How* ranks are assigned is the single pluggable seam: an [`Ordering`]. The
45//! flagship [`Geodesic`](ordering::Geodesic) ordering traces the "spine" of the
46//! art and reveals along it, so a serpent paints from one tip to the other, around
47//! every coil, with no per-art configuration.
48//!
49//! ```
50//! use inkling::{Art, ordering::{Ordering, Geodesic}};
51//!
52//! let art = Art::parse("/\\__/\\\n\\____/");
53//! let ranks = Geodesic::default().rank(&art);
54//!
55//! // The pure, dependency-free view: render the half-revealed frame as text.
56//! let frame = inkling::frame::to_string(&art, &ranks, 0.5);
57//! assert_eq!(frame.lines().count(), art.height() as usize);
58//! ```
59
60pub mod art;
61pub mod easing;
62pub mod frame;
63pub mod ordering;
64pub mod rank;
65
66#[cfg(feature = "terminal")]
67pub mod loader;
68#[cfg(feature = "terminal")]
69pub mod render;
70
71pub use art::Art;
72pub use easing::Easing;
73pub use ordering::Ordering;
74pub use rank::RankMap;
75
76#[cfg(feature = "terminal")]
77pub use loader::{Handle, Loader, ProgressIteratorExt};