pub struct SelectPrompt { /* private fields */ }Expand description
Builder returned by select().
Implementations§
Source§impl SelectPrompt
impl SelectPrompt
Sourcepub fn option(self, value: impl Into<String>, label: impl Into<String>) -> Self
pub fn option(self, value: impl Into<String>, label: impl Into<String>) -> Self
Append an option. value is the machine identifier, label is what
the user sees. Chain .hint("…") immediately after to attach a hint
to this option.
Examples found in repository?
examples/hello_prompt.rs (line 22)
12fn main() {
13 intro("Set up a new project");
14
15 let name = text("What's your name?")
16 .default("Anya") // accepted on Enter when buffer is empty
17 .placeholder("e.g. Anya") // dim hint shown before typing
18 .run()
19 .or_cancel("Cancelled.");
20
21 let stack = select("Pick a stack")
22 .option("rust", "Rust")
23 .option("ts", "TypeScript")
24 .option("py", "Python")
25 .run()
26 .or_cancel("Cancelled.");
27
28 let init_git = confirm("Initialise git?")
29 .default(true)
30 .run()
31 .or_cancel("Cancelled.");
32
33 outro(format!(
34 "{name} → {} ({} git)",
35 stack.label,
36 if init_git { "with" } else { "without" }
37 ));
38}More examples
examples/prompt.rs (line 29)
17fn main() -> cli_ui::prompt::Result<()> {
18 header!(
19 "prompt",
20 env!("CARGO_PKG_VERSION"),
21 "interactive prompt showcase",
22 "all prompt types"
23 );
24
25 intro("Set up a new project");
26
27 // ── 1. Single select with per-option hints ────────────────────────────────
28 let template = select("How would you like to start your new project?")
29 .option("basic", "A basic, helpful starter project")
30 .option("blog", "Use blog template")
31 .hint("Markdown-based blog with RSS feed support")
32 .option("docs", "Use docs (Starlight) template")
33 .hint("Documentation site with search and sidebar")
34 .option("minimal", "Use minimal (empty) template")
35 .hint("Just a Cargo.toml and src/lib.rs — nothing else")
36 .run()?;
37
38 // ── 2. Text input with validation ─────────────────────────────────────────
39 let dir = text("Where should we create your new project?")
40 .default("./my-app")
41 .placeholder("e.g. ./my-project")
42 .hint("Use a relative or absolute path")
43 .validate(|s| {
44 if s.starts_with('.') || s.starts_with('/') {
45 Ok(())
46 } else {
47 Err("path must start with . or /".into())
48 }
49 })
50 .run()?;
51
52 // ── 3. Multi select with per-option hints ─────────────────────────────────
53 let features = multiselect("Which features would you like to enable?")
54 .option("ts", "TypeScript")
55 .hint("JavaScript with syntax for types")
56 .option("tailwind", "Tailwind CSS")
57 .hint("A utility-first CSS framework")
58 .option("react", "React")
59 .hint("A JavaScript library for building user interfaces")
60 .option("vue", "Vue")
61 .hint("The Progressive JavaScript Framework")
62 .option("eslint", "ESLint")
63 .hint("Find and fix problems in your JavaScript code")
64 .run()?;
65
66 // ── 4. Grouped multiselect ────────────────────────────────────────────────
67 let tools = groupmultiselect("Select development tools:")
68 .group("Frontend")
69 .item("TypeScript")
70 .hint("JavaScript with syntax for types")
71 .item("ESLint")
72 .hint("Find and fix problems in your JS code")
73 .item("Prettier")
74 .hint("An opinionated code formatter")
75 .group("Backend")
76 .item("Node.js")
77 .hint("JavaScript runtime built on V8")
78 .item("Express")
79 .hint("Fast, unopinionated web framework")
80 .item("Prisma")
81 .hint("Next-generation ORM for Node.js")
82 .group("Testing")
83 .item("Jest")
84 .hint("Delightful JavaScript testing framework")
85 .item("Cypress")
86 .hint("End-to-end testing for the modern web")
87 .item("Vitest")
88 .hint("Vite-native unit testing framework")
89 .run()?;
90
91 // ── 5. Autocomplete ───────────────────────────────────────────────────────
92 let pkg = autocomplete("Search for a UI package:")
93 .option("astro", "Astro")
94 .hint("The web framework for content-based sites")
95 .option("react", "React")
96 .hint("A JavaScript library for building user interfaces")
97 .option("vue", "Vue")
98 .hint("The Progressive JavaScript Framework")
99 .option("svelte", "Svelte")
100 .hint("Cybernetically enhanced web apps")
101 .option("angular", "Angular")
102 .hint("Platform for building mobile & desktop web apps")
103 .option("solid", "SolidJS")
104 .hint("Simple and performant reactivity for building UIs")
105 .option("qwik", "Qwik")
106 .hint("HTML-first framework with instant interactivity")
107 .placeholder("Type to search...")
108 .max_items(5)
109 .run()?;
110
111 // ── 6. Confirm ────────────────────────────────────────────────────────────
112 let git = confirm("Initialize a new git repository?")
113 .default(true)
114 .run()?;
115
116 // ── 7. Secret ─────────────────────────────────────────────────────────────
117 let _token = secret("Enter your API token (optional)")
118 .allow_empty(true)
119 .hint("Leave empty to skip — you can set it later in .env")
120 .run()?;
121
122 // ── 8. Single-keypress select ─────────────────────────────────────────────
123 let action = select_key("Apply changes?")
124 .option('y', "Yes, apply")
125 .hint("write to disk")
126 .option('n', "No, abort")
127 .hint("discard everything")
128 .option('d', "Diff first")
129 .hint("preview the changes")
130 .run()?;
131 log::info(format!("you chose: {} ({})", action.key, action.label));
132
133 note(
134 "What happens next",
135 "We'll scaffold your project, install dependencies,\nand initialise git if you opted in.",
136 );
137
138 // ── 9. Spinner + tasks runner ─────────────────────────────────────────────
139 let s = spinner();
140 s.start("Resolving dependencies");
141 std::thread::sleep(std::time::Duration::from_millis(700));
142 s.message("Downloading 42 packages");
143 std::thread::sleep(std::time::Duration::from_millis(700));
144 s.stop("Resolved 42 packages");
145
146 // ── 10. Progress bar ──────────────────────────────────────────────────────
147 // Filled/empty bar rendered inside a spinner line. Advance in a loop
148 // (or from a worker thread) with `.advance(step, Some(message))`.
149 let pb = progress().style(ProgressStyle::Heavy).size(30).max(50);
150 pb.start("Downloading assets");
151 for i in 1..=50 {
152 std::thread::sleep(std::time::Duration::from_millis(30));
153 let msg = format!("asset {i}/50");
154 pb.advance(1, Some(msg));
155 }
156 pb.stop("Downloaded 50 assets");
157
158 tasks(vec![
159 Task::new("Compiling", |s| {
160 std::thread::sleep(std::time::Duration::from_millis(400));
161 s.message("crate cli-ui");
162 std::thread::sleep(std::time::Duration::from_millis(400));
163 Some("Compiled in 0.8s".into())
164 }),
165 Task::new("Running tests", |_| {
166 std::thread::sleep(std::time::Duration::from_millis(500));
167 Some("All 12 tests passed".into())
168 }),
169 ]);
170
171 log::success("Project ready");
172 outro("Happy hacking!");
173
174 let _ = prompt::Result::<()>::Ok(());
175
176 // ── Summary ───────────────────────────────────────────────────────────────
177 let feat_str = if features.is_empty() {
178 paint(DIM, "none")
179 } else {
180 paint(OK, &features.values().join(", "))
181 };
182
183 let tool_str = if tools.is_empty() {
184 paint(DIM, "none")
185 } else {
186 paint(OK, &tools.values().join(", "))
187 };
188
189 summary! {
190 done: "Project configured",
191 "template" => paint(CYAN, template.value()),
192 "directory" => paint(CYAN, &dir),
193 section,
194 "features" => feat_str,
195 "tools" => tool_str,
196 "ui package" => paint(CYAN, pkg.value()),
197 section,
198 "git" => paint(if git { OK } else { DIM }, if git { "yes" } else { "no" }),
199 }
200
201 Ok(())
202}Sourcepub fn hint(self, text: impl Into<String>) -> Self
pub fn hint(self, text: impl Into<String>) -> Self
Attach a hint to the most recently added option. Renders inline
next to the option label, e.g. Rust (systems programming).
Examples found in repository?
examples/prompt.rs (line 31)
17fn main() -> cli_ui::prompt::Result<()> {
18 header!(
19 "prompt",
20 env!("CARGO_PKG_VERSION"),
21 "interactive prompt showcase",
22 "all prompt types"
23 );
24
25 intro("Set up a new project");
26
27 // ── 1. Single select with per-option hints ────────────────────────────────
28 let template = select("How would you like to start your new project?")
29 .option("basic", "A basic, helpful starter project")
30 .option("blog", "Use blog template")
31 .hint("Markdown-based blog with RSS feed support")
32 .option("docs", "Use docs (Starlight) template")
33 .hint("Documentation site with search and sidebar")
34 .option("minimal", "Use minimal (empty) template")
35 .hint("Just a Cargo.toml and src/lib.rs — nothing else")
36 .run()?;
37
38 // ── 2. Text input with validation ─────────────────────────────────────────
39 let dir = text("Where should we create your new project?")
40 .default("./my-app")
41 .placeholder("e.g. ./my-project")
42 .hint("Use a relative or absolute path")
43 .validate(|s| {
44 if s.starts_with('.') || s.starts_with('/') {
45 Ok(())
46 } else {
47 Err("path must start with . or /".into())
48 }
49 })
50 .run()?;
51
52 // ── 3. Multi select with per-option hints ─────────────────────────────────
53 let features = multiselect("Which features would you like to enable?")
54 .option("ts", "TypeScript")
55 .hint("JavaScript with syntax for types")
56 .option("tailwind", "Tailwind CSS")
57 .hint("A utility-first CSS framework")
58 .option("react", "React")
59 .hint("A JavaScript library for building user interfaces")
60 .option("vue", "Vue")
61 .hint("The Progressive JavaScript Framework")
62 .option("eslint", "ESLint")
63 .hint("Find and fix problems in your JavaScript code")
64 .run()?;
65
66 // ── 4. Grouped multiselect ────────────────────────────────────────────────
67 let tools = groupmultiselect("Select development tools:")
68 .group("Frontend")
69 .item("TypeScript")
70 .hint("JavaScript with syntax for types")
71 .item("ESLint")
72 .hint("Find and fix problems in your JS code")
73 .item("Prettier")
74 .hint("An opinionated code formatter")
75 .group("Backend")
76 .item("Node.js")
77 .hint("JavaScript runtime built on V8")
78 .item("Express")
79 .hint("Fast, unopinionated web framework")
80 .item("Prisma")
81 .hint("Next-generation ORM for Node.js")
82 .group("Testing")
83 .item("Jest")
84 .hint("Delightful JavaScript testing framework")
85 .item("Cypress")
86 .hint("End-to-end testing for the modern web")
87 .item("Vitest")
88 .hint("Vite-native unit testing framework")
89 .run()?;
90
91 // ── 5. Autocomplete ───────────────────────────────────────────────────────
92 let pkg = autocomplete("Search for a UI package:")
93 .option("astro", "Astro")
94 .hint("The web framework for content-based sites")
95 .option("react", "React")
96 .hint("A JavaScript library for building user interfaces")
97 .option("vue", "Vue")
98 .hint("The Progressive JavaScript Framework")
99 .option("svelte", "Svelte")
100 .hint("Cybernetically enhanced web apps")
101 .option("angular", "Angular")
102 .hint("Platform for building mobile & desktop web apps")
103 .option("solid", "SolidJS")
104 .hint("Simple and performant reactivity for building UIs")
105 .option("qwik", "Qwik")
106 .hint("HTML-first framework with instant interactivity")
107 .placeholder("Type to search...")
108 .max_items(5)
109 .run()?;
110
111 // ── 6. Confirm ────────────────────────────────────────────────────────────
112 let git = confirm("Initialize a new git repository?")
113 .default(true)
114 .run()?;
115
116 // ── 7. Secret ─────────────────────────────────────────────────────────────
117 let _token = secret("Enter your API token (optional)")
118 .allow_empty(true)
119 .hint("Leave empty to skip — you can set it later in .env")
120 .run()?;
121
122 // ── 8. Single-keypress select ─────────────────────────────────────────────
123 let action = select_key("Apply changes?")
124 .option('y', "Yes, apply")
125 .hint("write to disk")
126 .option('n', "No, abort")
127 .hint("discard everything")
128 .option('d', "Diff first")
129 .hint("preview the changes")
130 .run()?;
131 log::info(format!("you chose: {} ({})", action.key, action.label));
132
133 note(
134 "What happens next",
135 "We'll scaffold your project, install dependencies,\nand initialise git if you opted in.",
136 );
137
138 // ── 9. Spinner + tasks runner ─────────────────────────────────────────────
139 let s = spinner();
140 s.start("Resolving dependencies");
141 std::thread::sleep(std::time::Duration::from_millis(700));
142 s.message("Downloading 42 packages");
143 std::thread::sleep(std::time::Duration::from_millis(700));
144 s.stop("Resolved 42 packages");
145
146 // ── 10. Progress bar ──────────────────────────────────────────────────────
147 // Filled/empty bar rendered inside a spinner line. Advance in a loop
148 // (or from a worker thread) with `.advance(step, Some(message))`.
149 let pb = progress().style(ProgressStyle::Heavy).size(30).max(50);
150 pb.start("Downloading assets");
151 for i in 1..=50 {
152 std::thread::sleep(std::time::Duration::from_millis(30));
153 let msg = format!("asset {i}/50");
154 pb.advance(1, Some(msg));
155 }
156 pb.stop("Downloaded 50 assets");
157
158 tasks(vec![
159 Task::new("Compiling", |s| {
160 std::thread::sleep(std::time::Duration::from_millis(400));
161 s.message("crate cli-ui");
162 std::thread::sleep(std::time::Duration::from_millis(400));
163 Some("Compiled in 0.8s".into())
164 }),
165 Task::new("Running tests", |_| {
166 std::thread::sleep(std::time::Duration::from_millis(500));
167 Some("All 12 tests passed".into())
168 }),
169 ]);
170
171 log::success("Project ready");
172 outro("Happy hacking!");
173
174 let _ = prompt::Result::<()>::Ok(());
175
176 // ── Summary ───────────────────────────────────────────────────────────────
177 let feat_str = if features.is_empty() {
178 paint(DIM, "none")
179 } else {
180 paint(OK, &features.values().join(", "))
181 };
182
183 let tool_str = if tools.is_empty() {
184 paint(DIM, "none")
185 } else {
186 paint(OK, &tools.values().join(", "))
187 };
188
189 summary! {
190 done: "Project configured",
191 "template" => paint(CYAN, template.value()),
192 "directory" => paint(CYAN, &dir),
193 section,
194 "features" => feat_str,
195 "tools" => tool_str,
196 "ui package" => paint(CYAN, pkg.value()),
197 section,
198 "git" => paint(if git { OK } else { DIM }, if git { "yes" } else { "no" }),
199 }
200
201 Ok(())
202}Sourcepub fn prompt_hint(self, text: impl Into<String>) -> Self
pub fn prompt_hint(self, text: impl Into<String>) -> Self
One-line hint shown under the prompt label (not per-option).
Sourcepub fn max_items(self, n: usize) -> Self
pub fn max_items(self, n: usize) -> Self
Number of option rows visible at once. Longer lists scroll with
↑ N more / ↓ N more indicators.
Sourcepub fn run(self) -> Result<Selected>
pub fn run(self) -> Result<Selected>
Run the prompt to completion. Panics if no options were added.
Examples found in repository?
examples/hello_prompt.rs (line 25)
12fn main() {
13 intro("Set up a new project");
14
15 let name = text("What's your name?")
16 .default("Anya") // accepted on Enter when buffer is empty
17 .placeholder("e.g. Anya") // dim hint shown before typing
18 .run()
19 .or_cancel("Cancelled.");
20
21 let stack = select("Pick a stack")
22 .option("rust", "Rust")
23 .option("ts", "TypeScript")
24 .option("py", "Python")
25 .run()
26 .or_cancel("Cancelled.");
27
28 let init_git = confirm("Initialise git?")
29 .default(true)
30 .run()
31 .or_cancel("Cancelled.");
32
33 outro(format!(
34 "{name} → {} ({} git)",
35 stack.label,
36 if init_git { "with" } else { "without" }
37 ));
38}More examples
examples/prompt.rs (line 36)
17fn main() -> cli_ui::prompt::Result<()> {
18 header!(
19 "prompt",
20 env!("CARGO_PKG_VERSION"),
21 "interactive prompt showcase",
22 "all prompt types"
23 );
24
25 intro("Set up a new project");
26
27 // ── 1. Single select with per-option hints ────────────────────────────────
28 let template = select("How would you like to start your new project?")
29 .option("basic", "A basic, helpful starter project")
30 .option("blog", "Use blog template")
31 .hint("Markdown-based blog with RSS feed support")
32 .option("docs", "Use docs (Starlight) template")
33 .hint("Documentation site with search and sidebar")
34 .option("minimal", "Use minimal (empty) template")
35 .hint("Just a Cargo.toml and src/lib.rs — nothing else")
36 .run()?;
37
38 // ── 2. Text input with validation ─────────────────────────────────────────
39 let dir = text("Where should we create your new project?")
40 .default("./my-app")
41 .placeholder("e.g. ./my-project")
42 .hint("Use a relative or absolute path")
43 .validate(|s| {
44 if s.starts_with('.') || s.starts_with('/') {
45 Ok(())
46 } else {
47 Err("path must start with . or /".into())
48 }
49 })
50 .run()?;
51
52 // ── 3. Multi select with per-option hints ─────────────────────────────────
53 let features = multiselect("Which features would you like to enable?")
54 .option("ts", "TypeScript")
55 .hint("JavaScript with syntax for types")
56 .option("tailwind", "Tailwind CSS")
57 .hint("A utility-first CSS framework")
58 .option("react", "React")
59 .hint("A JavaScript library for building user interfaces")
60 .option("vue", "Vue")
61 .hint("The Progressive JavaScript Framework")
62 .option("eslint", "ESLint")
63 .hint("Find and fix problems in your JavaScript code")
64 .run()?;
65
66 // ── 4. Grouped multiselect ────────────────────────────────────────────────
67 let tools = groupmultiselect("Select development tools:")
68 .group("Frontend")
69 .item("TypeScript")
70 .hint("JavaScript with syntax for types")
71 .item("ESLint")
72 .hint("Find and fix problems in your JS code")
73 .item("Prettier")
74 .hint("An opinionated code formatter")
75 .group("Backend")
76 .item("Node.js")
77 .hint("JavaScript runtime built on V8")
78 .item("Express")
79 .hint("Fast, unopinionated web framework")
80 .item("Prisma")
81 .hint("Next-generation ORM for Node.js")
82 .group("Testing")
83 .item("Jest")
84 .hint("Delightful JavaScript testing framework")
85 .item("Cypress")
86 .hint("End-to-end testing for the modern web")
87 .item("Vitest")
88 .hint("Vite-native unit testing framework")
89 .run()?;
90
91 // ── 5. Autocomplete ───────────────────────────────────────────────────────
92 let pkg = autocomplete("Search for a UI package:")
93 .option("astro", "Astro")
94 .hint("The web framework for content-based sites")
95 .option("react", "React")
96 .hint("A JavaScript library for building user interfaces")
97 .option("vue", "Vue")
98 .hint("The Progressive JavaScript Framework")
99 .option("svelte", "Svelte")
100 .hint("Cybernetically enhanced web apps")
101 .option("angular", "Angular")
102 .hint("Platform for building mobile & desktop web apps")
103 .option("solid", "SolidJS")
104 .hint("Simple and performant reactivity for building UIs")
105 .option("qwik", "Qwik")
106 .hint("HTML-first framework with instant interactivity")
107 .placeholder("Type to search...")
108 .max_items(5)
109 .run()?;
110
111 // ── 6. Confirm ────────────────────────────────────────────────────────────
112 let git = confirm("Initialize a new git repository?")
113 .default(true)
114 .run()?;
115
116 // ── 7. Secret ─────────────────────────────────────────────────────────────
117 let _token = secret("Enter your API token (optional)")
118 .allow_empty(true)
119 .hint("Leave empty to skip — you can set it later in .env")
120 .run()?;
121
122 // ── 8. Single-keypress select ─────────────────────────────────────────────
123 let action = select_key("Apply changes?")
124 .option('y', "Yes, apply")
125 .hint("write to disk")
126 .option('n', "No, abort")
127 .hint("discard everything")
128 .option('d', "Diff first")
129 .hint("preview the changes")
130 .run()?;
131 log::info(format!("you chose: {} ({})", action.key, action.label));
132
133 note(
134 "What happens next",
135 "We'll scaffold your project, install dependencies,\nand initialise git if you opted in.",
136 );
137
138 // ── 9. Spinner + tasks runner ─────────────────────────────────────────────
139 let s = spinner();
140 s.start("Resolving dependencies");
141 std::thread::sleep(std::time::Duration::from_millis(700));
142 s.message("Downloading 42 packages");
143 std::thread::sleep(std::time::Duration::from_millis(700));
144 s.stop("Resolved 42 packages");
145
146 // ── 10. Progress bar ──────────────────────────────────────────────────────
147 // Filled/empty bar rendered inside a spinner line. Advance in a loop
148 // (or from a worker thread) with `.advance(step, Some(message))`.
149 let pb = progress().style(ProgressStyle::Heavy).size(30).max(50);
150 pb.start("Downloading assets");
151 for i in 1..=50 {
152 std::thread::sleep(std::time::Duration::from_millis(30));
153 let msg = format!("asset {i}/50");
154 pb.advance(1, Some(msg));
155 }
156 pb.stop("Downloaded 50 assets");
157
158 tasks(vec![
159 Task::new("Compiling", |s| {
160 std::thread::sleep(std::time::Duration::from_millis(400));
161 s.message("crate cli-ui");
162 std::thread::sleep(std::time::Duration::from_millis(400));
163 Some("Compiled in 0.8s".into())
164 }),
165 Task::new("Running tests", |_| {
166 std::thread::sleep(std::time::Duration::from_millis(500));
167 Some("All 12 tests passed".into())
168 }),
169 ]);
170
171 log::success("Project ready");
172 outro("Happy hacking!");
173
174 let _ = prompt::Result::<()>::Ok(());
175
176 // ── Summary ───────────────────────────────────────────────────────────────
177 let feat_str = if features.is_empty() {
178 paint(DIM, "none")
179 } else {
180 paint(OK, &features.values().join(", "))
181 };
182
183 let tool_str = if tools.is_empty() {
184 paint(DIM, "none")
185 } else {
186 paint(OK, &tools.values().join(", "))
187 };
188
189 summary! {
190 done: "Project configured",
191 "template" => paint(CYAN, template.value()),
192 "directory" => paint(CYAN, &dir),
193 section,
194 "features" => feat_str,
195 "tools" => tool_str,
196 "ui package" => paint(CYAN, pkg.value()),
197 section,
198 "git" => paint(if git { OK } else { DIM }, if git { "yes" } else { "no" }),
199 }
200
201 Ok(())
202}Trait Implementations§
Source§impl Prompt for SelectPrompt
impl Prompt for SelectPrompt
Source§fn handle(&mut self, key: Key) -> Step<Selected>
fn handle(&mut self, key: Key) -> Step<Selected>
Apply a key press to the prompt’s internal state. Return: Read more
Source§fn render(&self, _ctx: RenderCtx<'_>) -> Frame
fn render(&self, _ctx: RenderCtx<'_>) -> Frame
Render the prompt’s current state as one frame (a
Vec<String>,
one entry per terminal row). The runner takes care of writing the
frame and clearing it on the next iteration — prompts never call
eprintln! themselves.Source§fn render_answered(&self, value: &Selected) -> Frame
fn render_answered(&self, value: &Selected) -> Frame
Render the prompt’s post-submission display. Typically the
◇ question / │ value / │ triple from theme::answered.Source§fn run_fallback(self) -> Result<Selected>
fn run_fallback(self) -> Result<Selected>
Optional non-interactive fallback for piped/CI environments. The
default is to refuse — most prompts override this with a numeric
or line-buffered alternative.
Auto Trait Implementations§
impl Freeze for SelectPrompt
impl RefUnwindSafe for SelectPrompt
impl Send for SelectPrompt
impl Sync for SelectPrompt
impl Unpin for SelectPrompt
impl UnsafeUnpin for SelectPrompt
impl UnwindSafe for SelectPrompt
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more