Struct conciliator::print::List
source · pub struct List<H, I, F, P> { /* private fields */ }
Expand description
List of things to print, with a short description
§Introduction
For example:
let con = conciliator::init();
use conciliator::{Conciliator, List};
con.print(List::new("numbers", 0..3));
Prints:
[ > ] 3 numbers:
→ 0
→ 1
→ 2
The basic List::new
:
- indents the items and adds a little arrow:
→
- introduces the list with a description and its length
- does not print anything if the iterator is empty
- works for any
ExactSizeIterator
whose items implement eitherInline
orDisplay
While none of these small features are exceptionally tedious to write manually, to do so frequently would be very inconvenient, and so, this struct was created.
§Implementation
It’s not necessary to understand these implementation details, this section may be skipped.
The List
is rather flexible, which unfortunately means it has several generic parameters:
- the
Prefixer
controls how/if the items are indented, - the
Formatter
formats and prints the items - the
Header
can print an introduction at the beginning
The “default” Formatter
(i.e. what the constructors for this type return) is a PushableFmt<M>
.
The M
here is generic without constraints: just like with Pushable
, it is up to type inference at the call site to pick the correct one.
So, for a List
of Inline
or Display
items, the correct marker is inferred when it is printed because printing is only implemented when formatting is.
When the List
is given a different Formatter
using with_formatter
or with_wrap
, the generic M
is inferred to be ()
.
This is because those methods are only implemented for PushableFmt<()>
(which is useless) - if they were implemented for any M
, using them would somewhat counter-intuitively require type annotations for a type that’s being replaced anyway.
§Method overview
Constructors:
new(header, iter)
-Pushable
header andExactSizeIterator
, the description will include the countuncounted(header, iter)
- Same as above, but without the count orExactSizeIterator
requirementheadless(iter)
- Without headerindexed(iter)
- Without header, each item prefixed with its index, starting from 1
Builders:
with_header(header)
- Add aPushable
header (only available if there isn’t one already)with_count(header)
- Same as above but requiresExactSizeIterator
to show the count likenew()
with_formatter(formatter)
- Use aFormatter
to control how items are written into theBuffer
with_wrap(wrap_fn)
- Like above, but with a function that wraps each item with anInline
implementor
Printing:
print_to(printer)
-Print
without importing the trait. Arguably nicer thancon.print(List::new(…))
print_and_count(printer)
- As above, but also returns the count of items printed
§Examples
Minimal example:
use conciliator::{Conciliator, List};
let con = conciliator::init();
con.print(List::new("numbers", 0..3));
Basic example:
use conciliator::{Conciliator, List, Wrap};
let con = conciliator::init();
let uuids = [
"37312de1-3f29-4db2-a437-b03de26ce06d",
"239229f8-ff65-4986-8ca7-44ce65a6d66b",
"61951efa-e5f6-422e-862c-a793af716866"
];
let list = List::new("UUIDs", uuids.iter()).with_wrap(Wrap::Alpha);
con.print(list);
Alternatively, the last two lines can be rewritten as:
List::new("UUIDs", uuids.iter())
.with_wrap(Wrap::Alpha)
.print_to(&con);
Either way, both print:
[ > ] 3 UUIDs:
→ 37312de1-3f29-4db2-a437-b03de26ce06d
→ 239229f8-ff65-4986-8ca7-44ce65a6d66b
→ 61951efa-e5f6-422e-862c-a793af716866
Finally, a slightly more complicated example that prints the environment variables. It utilizes a custom wrapper type and prints an error if the iterator yields no items:
use conciliator::{Conciliator, Buffer, Paint, Inline, List};
let con = conciliator::init();
struct EnvVar((String, String));
impl Inline for EnvVar {
fn inline(&self, buffer: &mut Buffer) {
buffer
.push_beta_bold(&self.0.0)
.push(": ")
.push(&self.0.1);
}
}
let printed = List::headless(std::env::vars())
.with_header("Environment variables")
.with_wrap(EnvVar)
.print_and_count(&con);
if printed == 0 {
con.error("No environment variables set!");
}
The result looks like this (though this is truncated and without colors):
[ > ] Environment variables:
→ CARGO_CRATE_NAME: conciliator
→ CARGO_PKG_LICENSE: GPL-3.0-or-later
→ CARGO_PKG_NAME: conciliator
→ CARGO_PKG_REPOSITORY: https://git.sr.ht/~xaos/conciliator
→ CARGO_PKG_VERSION: 0.3.3
Check out the example binary to see it in action!
Implementations§
source§impl<I, T, MT, H, MH> List<PushableHdr<MH, H>, I, PushableFmt<MT>, ArrowPrefix>where
I: ExactSizeIterator<Item = T>,
impl<I, T, MT, H, MH> List<PushableHdr<MH, H>, I, PushableFmt<MT>, ArrowPrefix>where
I: ExactSizeIterator<Item = T>,
sourcepub fn new(header: H, iter: I) -> Self
pub fn new(header: H, iter: I) -> Self
A List
introduced by a header, showing the amount of items in it
Requires iter
to be an ExactSizeIterator
.
The header
may be any implementor of Pushable
- which is any type implementing Inline
or Display
(for types that do both it gets a little finicky).
So, for example:
con.print(List::new("numbers", 0..3));
Prints:
[ > ] 3 numbers:
→ 0
→ 1
→ 2
Note that the header
here is only "numbers"
; the tag, amount 3
, and the :
are added automatically.
The returned List
is Print
able as-is if the items are Pushable
.
Otherwise, one of List::with_formatter
or List::with_wrap
has to be used to specify how the items should be printed.
struct Number(usize); // doesn't implement Display or Inline
List::new("numbers", (0..3).map(Number))
.with_wrap(|n| Wrap::Alpha(n.0))
.print_to(&con);
source§impl<I, MT, H, MH> List<PushableHdr<MH, H>, I, PushableFmt<MT>, ArrowPrefix>
impl<I, MT, H, MH> List<PushableHdr<MH, H>, I, PushableFmt<MT>, ArrowPrefix>
sourcepub fn uncounted(header: H, iter: I) -> Self
pub fn uncounted(header: H, iter: I) -> Self
A List
introduced by a header
Just like List::new()
but without showing the amount of items.
Consequently does not require an ExactSizeIterator
.
The header
may be any implementor of Pushable
- which is any type implementing Inline
or Display
(for types that do both it gets a little finicky).
So, for example:
con.print(List::uncounted("Some numbers", (0..).take(3)));
Produces something like:
[ > ] Some numbers:
→ 0
→ 1
→ 2
Note that the header
here is only "Some numbers"
.
The tag and the :
are added automatically.
source§impl<I, M> List<NoHeader, I, PushableFmt<M>, ArrowPrefix>
impl<I, M> List<NoHeader, I, PushableFmt<M>, ArrowPrefix>
sourcepub fn headless(iter: I) -> Self
pub fn headless(iter: I) -> Self
A List
without introduction
By itself, the list returned by this prints only the items without any header:
con.print(List::headless(0..3));
→ 0
→ 1
→ 2
However, a header can be added using List::with_header
(without the count of items) or List::with_count
(with).
con.print(List::headless(0..3).with_count("numbers"));
[ > ] 3 numbers:
→ 0
→ 1
→ 2
source§impl<I, M> List<NoHeader, I, PushableFmt<M>, Indexer>
impl<I, M> List<NoHeader, I, PushableFmt<M>, Indexer>
sourcepub fn indexed(iter: I) -> Self
pub fn indexed(iter: I) -> Self
A List
printing each item with its index, starting at 1 (without introduction)
By itself, the list returned by this does not print a header:
con.print(List::indexed(0..3));
[1] - 0
[2] - 1
[3] - 2
A header can be added using List::with_header
(without the count of items) or List::with_count
(with).
con.print(List::indexed(0..3).with_count("numbers"));
[ > ] 3 numbers:
[1] - 0
[2] - 1
[3] - 2
source§impl<H, I, P> List<H, I, PushableFmt<()>, P>
impl<H, I, P> List<H, I, PushableFmt<()>, P>
sourcepub fn with_formatter<F>(self, formatter: F) -> List<H, I, F, P>
pub fn with_formatter<F>(self, formatter: F) -> List<H, I, F, P>
Use a Formatter
to format items
Here’s a simple example using a Formatter
to write OsString
s into the Buffer
losslessly.
use std::ffi::OsString;
use std::os::unix::ffi::OsStrExt;
use std::io::Write;
use conciliator::{List, Buffer};
let con = conciliator::init();
fn format_os_string(buf: &mut Buffer, os_string: OsString) {
buf.write_all(&os_string.as_bytes()).unwrap();
}
List::new("arguments", std::env::args_os())
.with_formatter(format_os_string)
.print_to(&con);
This prints the arguments to the process unchanged, even if they contain invalid UTF-8 for some reason.
[ > ] 1 arguments:
→ /tmp/rustdoctestyyoYAo/rust_out
Unfortunately, it also shows some of the limitations of the Formatter
trait: for one, fallible formatting is not supported, which is why the std::io::Result
from write_all
is simply unwrap
ped (not that there’s much error handling to be done when writing to a buffer fails).
And secondly, the arguments to the formatting function need to match the iterator exactly, i.e. format_os_string
has to take an OsString
by value even though intuitively, taking the OsString
by reference or even an &OsStr
would be sufficient here.
Another slight inconvenience is that, while a closure can be used as a Formatter
, doing so will require type-annotating its arguments.
List::new("arguments", std::env::args_os())
.with_formatter(|buf: &mut Buffer, os_string: OsString| {
buf.write_all(&os_string.as_bytes()).unwrap();
})
.print_to(&con);
This may be improved in the future by adding a method that is less general.
source§impl<H, I: Iterator<Item = T>, T, P> List<H, I, PushableFmt<()>, P>
impl<H, I: Iterator<Item = T>, T, P> List<H, I, PushableFmt<()>, P>
sourcepub fn with_wrap<F, W>(self, wrap_fn: F) -> List<H, I, WrapFmt<F>, P>
pub fn with_wrap<F, W>(self, wrap_fn: F) -> List<H, I, WrapFmt<F>, P>
Use a function or closure to wrap items for printing
Here is the minimal example adjusted to print the numbers with the Alpha
color:
List::new("numbers", 0..3)
.with_wrap(Wrap::Alpha)
.print_to(&con);
Unfortunately the terminal formatting doesn’t render here, but the results are unsurprising (only the numbers themselves are colored).
The wrapper function gets applied to each item, in order.
See WrapFmt
for more.
source§impl<I, F, P> List<NoHeader, I, F, P>
impl<I, F, P> List<NoHeader, I, F, P>
sourcepub fn with_header<M, T>(self, header: T) -> List<PushableHdr<M, T>, I, F, P>
pub fn with_header<M, T>(self, header: T) -> List<PushableHdr<M, T>, I, F, P>
Use something Pushable
to introduce the list
Doesn’t add the count of items automatically.
source§impl<I: ExactSizeIterator<Item = T>, T, F, P> List<NoHeader, I, F, P>
impl<I: ExactSizeIterator<Item = T>, T, F, P> List<NoHeader, I, F, P>
sourcepub fn with_count<M, H>(self, header: H) -> List<PushableHdr<M, H>, I, F, P>
pub fn with_count<M, H>(self, header: H) -> List<PushableHdr<M, H>, I, F, P>
Use something Pushable
to introduce the list, showing the count
The count of items gets added automatically, before header
.
source§impl<H, I, T, P, F> List<H, I, F, P>
impl<H, I, T, P, F> List<H, I, F, P>
sourcepub fn print_and_count<C>(self, con: &C) -> usizewhere
C: Conciliator + ?Sized,
pub fn print_and_count<C>(self, con: &C) -> usizewhere
C: Conciliator + ?Sized,
Print this List
with a Conciliator
and return the count of items
The List
doesn’t print anything if there are no items, but the user might need to be informed if the iterator was expected to not be empty.
Since Print::print
does not have a return value and because the iterator needs to be consumed fully to know how many items it contained, this method must be used instead of Print::print
to also return the count.
let search = (0..10).filter(|i| i % 3 == 0);
let printed_something = List::uncounted("Numbers found", search)
.with_wrap(Wrap::Beta)
.print_and_count(&con)
.gt(&0);
if !printed_something {con.error("No numbers found!");}
sourcepub fn print_to<C: Conciliator + ?Sized>(self, con: &C)
pub fn print_to<C: Conciliator + ?Sized>(self, con: &C)
Print this List
with a Conciliator
This is exactly the same as using the Print::print
function, provided only for the convenience of not needing to have Print
in scope.
When using the with_*
methods to build the List
, this composes nicer than using the .print(…)
method on the Conciliator
.
For example, this:
List::headless(0..3)
.with_count("numbers")
.with_wrap(Wrap::Beta)
.print_to(&con);
is nicer than this:
con.print(List::headless(0..3).with_count("numbers").with_wrap(Wrap::Beta));