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
//! Typed options: one list of `(value, label)` pairs a choice field, a select
//! filter and a column share.
use crateText;
/// A closed set of values, each with its label.
///
/// Derive it on a unit-variant enum with
/// [`#[derive(Options)]`](crate::Options): each variant's value is its
/// `snake_case` name and its label the message `option-{enum}.{variant}`, which reads the name
/// in sentence case when no catalog holds it, and `#[option(value = "..", label = "..")]`
/// overrides either, the label as plain text.
///
/// The derive also makes the enum a [`FormScalar`](crate::FormScalar) that a
/// form posts as its value and a column reads as its label, so a model field
/// of the enum's type, derived `toasty::Embed`, binds without a string in
/// between:
///
/// ```rust
/// # use tablo_core::{Field, SelectFilter, Table, TextColumn, lens, Options};
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, toasty::Embed, tablo_core::Options)]
/// enum Status {
/// Draft,
/// #[option(label = "Live")]
/// Published,
/// }
///
/// #[derive(Debug, Clone, toasty::Model, tablo_core::ModelColumns)]
/// struct Post {
/// #[key]
/// #[auto]
/// id: uuid::Uuid,
/// status: Status,
/// }
///
/// Field::choice(lens!(Post.status)).options(Status::options());
/// SelectFilter::of(lens!(Post.status));
/// Table::new(TextColumn::new(lens!(Post.status))).group_by(lens!(Post.status));
/// Post::filter(Post::fields().status().eq(Status::Published));
/// ```
///
/// Toasty stores the variant under its own discriminant, `snake_case` by
/// default; the option's value is only the form's spelling. A `String` field
/// takes the same list, storing the value itself:
/// `SelectFilter::new(lens!(Post.kind), Kind::options())`.
///
/// `#[option(color = "…")]` names the [`Color`](crate::Color) a badge shows a variant in, and
/// `#[option(icon = …)]` the [`IconData`](topcoat::icon::IconData) a
/// [`TextColumn`](crate::TextColumn) shows before it and an [`IconColumn`](crate::IconColumn)
/// shows in its place:
///
/// ```rust
/// #[derive(Debug, Clone, Copy, PartialEq, Eq, toasty::Embed, tablo_core::Options)]
/// enum Status {
/// #[option(color = "warning", icon = tablo_ui::icons::INFO)]
/// Draft,
/// #[option(color = "success", icon = tablo_ui::icons::CIRCLE_CHECK)]
/// Published,
/// }
/// ```
///
/// The derive also gives the enum `value()`, `label()` and `from_value()`, and `ALL`, every
/// variant in declaration order, for a figure per option:
///
/// ```rust
/// # #[derive(Debug, Clone, Copy, PartialEq, Eq, toasty::Embed, tablo_core::Options)]
/// # enum Status { Draft, Published }
/// for status in Status::ALL {
/// println!("{}", status.value());
/// }
/// ```
/// An optional field offers its type's options; an empty submission reads as `None`.