1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//! # TBL
//! (T)erm (B)ar (time)Line.
//!
//! ## Example
//!
//! ```
//! use tbl::Renderer;
//!
//! let data = vec![(0., 2.), (3., 4.)];
//! let rendered = Renderer::new(data.as_slice(), &|&e| e, &|_| None::<String>) // explicit type for Option<Label>
//! .with_length(42)
//! .render()
//! .unwrap();
//! for line in rendered.iter().flatten() {
//! assert_eq!(line, "===================== ===========");
//! }
//! ```
//!
//! ## Custom Data and Renderer
//!
//! ```
//! use tbl::{Block, RenderBlock, Renderer, TBLError, Bound};
//!
//! struct CustomData {
//! bounds: (usize, usize),
//! label: String // must be Clone + Debug
//! }
//!
//! fn bounds(cd: &CustomData)-> Bound {
//! let (a, b) = cd.bounds;
//! (a as f64, b as f64)
//! }
//!
//! fn label(cd: &CustomData)-> Option<String> {
//! Some(cd.label.clone())
//! }
//!
//! fn render(b: &Block<String>) -> RenderBlock {
//! match b {
//! Block::Space(length) => RenderBlock::Space("\u{2606}".repeat(*length)),
//! Block::Segment(length, label) => {
//! let mut truncated = label.clone().unwrap_or_default();
//! truncated.truncate(*length);
//! RenderBlock::Block(format!(
//! "{}{}",
//! truncated,
//! "\u{2605}".repeat(*length - truncated.len())
//! ))
//! }
//! }
//! }
//!
//! let data = vec![CustomData{bounds: (0, 2), label: "hello".to_string()}, CustomData{bounds: (3, 4), label: "world!".to_string()}];
//! let rendered = Renderer::new(data.as_slice(), &bounds, &label)
//! .with_length(60)
//! .with_renderer(&render)
//! .render().unwrap();
//! for line in rendered.iter().flatten() {
//! assert_eq!(line, "hello★★★★★★★★★★★★★★★★★★★★★★★★★☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆world!★★★★★★★★★");
//! }
//! ```
use Debug;
use Error;
pub const EPSILON: f64 = 0.1; // < 1/8
pub type Bound = ;
pub use Renderer;
pub use RenderBlock;
/// Blocks are built, then rendered using a `BlockRenderer`.