#[non_exhaustive]pub struct Candidate<'a> {
pub value: &'a str,
pub label: &'a str,
pub detail: Option<&'a str>,
}Expand description
One entry in a field’s suggestion list.
A suggestion-only type rather than a fourth member on Choice, ruled by
Max 2026-08-21 (1fcf2e9b). The two are near-identical and that is the
drift risk the ruling accepted, so the mitigation is written here: an
option and a candidate are submitted the same way and read differently.
An option is a thing you pick from a known set, and the set is the whole of
what there is. A candidate is a thing you are being oriented toward out of
a set nobody can see, which is why it carries detail and
an option does not.
This reverses a position quasi-router stated in its own doc, that a
candidate is Choice “because a candidate is submitted under one string
and read under another, which is what an option is”. True and not
sufficient: how a thing is submitted was never the half that differed.
§Why the second string is not folded into the label
Because every renderer wants it separately, and the two measured sites both
draw it by hand today. The MNW server’s tag box computes its context as the
parent path – “the parent path orients an otherwise ambiguous leaf:
‘Format’ appears under audio, software, writing, and video” – and a list of
four identical rows reading “Format” is not a usable list. In a webview the
second string is styled differently, in a terminal it wants the remaining
columns rather than a dash, and in neither is it part of what the typed
value matches against. Choice::new(slug, format!("{label} - {context}"))
loses all three of those facts, which is the condition this type exists to
end.
§No unavailable
Choice::unavailable has no counterpart here, and the omission is the
implementer’s call recorded rather than an oversight. A suggestion that
cannot be picked is arguably not a suggestion: an option list is a fixed set
a user is owed an explanation about, and a candidate list is whatever a
route decided to offer, so a route with nothing to say simply does not offer
the row. Add it if a measured site ever wants it.
§What it does not carry, and where that lives
What happens when a candidate is picked. Picking is local by default – it
writes value into the field that owns the list – and a
candidate that does something else says so with an action. An action is not
a word this crate has, exactly as Field here has no suggests member,
so both live on the router’s owned mirror of this type. Ruled the same day
(ed1fa86f).
#[non_exhaustive] from birth. Non-negotiable and the reason is on the
sibling: Choice took it at 0.28.0 only after unavailable broke 40
literal sites in six repos, and a new type repeating that would be the third
time the tree learned it.
Added 0.35.0.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.value: &'a strWhat is submitted, and what picking writes into the field.
label: &'a strWhat is read.
detail: Option<&'a str>The second line: what orients this candidate among rows that read alike.
Optional because a candidate list whose labels are already distinct
wants nothing here, and a renderer given None draws one line rather
than an empty second one.
Implementations§
Source§impl<'a> Candidate<'a>
impl<'a> Candidate<'a>
Sourcepub const fn plain(value: &'a str) -> Self
pub const fn plain(value: &'a str) -> Self
A candidate whose submitted value is also its label.
Sourcepub const fn new(value: &'a str, label: &'a str) -> Self
pub const fn new(value: &'a str, label: &'a str) -> Self
A candidate that submits one string and reads as another.
A constructor rather than a literal, which is what #[non_exhaustive]
costs and buys: outside this crate the struct cannot be built by naming
its members, so every call site goes through here and the next member
added breaks none of them.