• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

veeso / tui-realm-stdlib / 21209471148

21 Jan 2026 12:24PM UTC coverage: 72.486% (-0.1%) from 72.632%
21209471148

Pull #53

github

web-flow
Merge 237158c92 into 95c949ee0
Pull Request #53: Apply changes for ratatui 0.30

43 of 90 new or added lines in 9 files covered. (47.78%)

1 existing line in 1 file now uncovered.

3662 of 5052 relevant lines covered (72.49%)

4.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.37
/src/components/select.rs
1
//! ## Select
2
//!
3
//! `Select` represents a select field, like in HTML. The size for the component must be 3 (border + selected) + the quantity of rows
4
//! you want to display other options when opened (at least 3)
5

6
use tuirealm::command::{Cmd, CmdResult, Direction};
7
use tuirealm::props::{
8
    AttrValue, Attribute, BorderSides, Borders, Color, LineStatic, PropPayload, PropValue, Props,
9
    Style, TextModifiers, Title,
10
};
11
use tuirealm::ratatui::text::Line as Spans;
12
use tuirealm::ratatui::{
13
    layout::{Constraint, Direction as LayoutDirection, Layout, Rect},
14
    widgets::{List, ListItem, ListState, Paragraph},
15
};
16
use tuirealm::{Frame, MockComponent, State, StateValue};
17

18
use crate::utils::borrow_clone_line;
19

20
// -- states
21

22
/// ## SelectStates
23
///
24
/// Component states
25
#[derive(Default)]
26
pub struct SelectStates {
27
    /// Available choices
28
    pub choices: Vec<String>,
29
    /// Currently selected choice
30
    pub selected: usize,
31
    /// Choice selected before opening the tab
32
    pub previously_selected: usize,
33
    pub tab_open: bool,
34
}
35

36
impl SelectStates {
37
    /// ### next_choice
38
    ///
39
    /// Move choice index to next choice
40
    pub fn next_choice(&mut self, rewind: bool) {
22✔
41
        if self.tab_open {
22✔
42
            if rewind && self.selected + 1 >= self.choices.len() {
18✔
43
                self.selected = 0;
2✔
44
            } else if self.selected + 1 < self.choices.len() {
16✔
45
                self.selected += 1;
12✔
46
            }
12✔
47
        }
4✔
48
    }
22✔
49

50
    /// ### prev_choice
51
    ///
52
    /// Move choice index to previous choice
53
    pub fn prev_choice(&mut self, rewind: bool) {
22✔
54
        if self.tab_open {
22✔
55
            if rewind && self.selected == 0 && !self.choices.is_empty() {
16✔
56
                self.selected = self.choices.len() - 1;
2✔
57
            } else if self.selected > 0 {
14✔
58
                self.selected -= 1;
12✔
59
            }
12✔
60
        }
6✔
61
    }
22✔
62

63
    /// ### set_choices
64
    ///
65
    /// Set SelectStates choices from a vector of str
66
    /// In addition resets current selection and keep index if possible or set it to the first value
67
    /// available
68
    pub fn set_choices(&mut self, choices: impl Into<Vec<String>>) {
28✔
69
        self.choices = choices.into();
28✔
70
        // Keep index if possible
14✔
71
        if self.selected >= self.choices.len() {
28✔
72
            self.selected = match self.choices.len() {
4✔
73
                0 => 0,
2✔
74
                l => l - 1,
2✔
75
            };
76
        }
24✔
77
    }
28✔
78

79
    pub fn select(&mut self, i: usize) {
6✔
80
        if i < self.choices.len() {
6✔
81
            self.selected = i;
6✔
82
        }
6✔
83
    }
6✔
84

85
    /// ### close_tab
86
    ///
87
    /// Close tab
88
    pub fn close_tab(&mut self) {
12✔
89
        self.tab_open = false;
12✔
90
    }
12✔
91

92
    /// ### open_tab
93
    ///
94
    /// Open tab
95
    pub fn open_tab(&mut self) {
12✔
96
        self.previously_selected = self.selected;
12✔
97
        self.tab_open = true;
12✔
98
    }
12✔
99

100
    /// Cancel tab open
101
    pub fn cancel_tab(&mut self) {
2✔
102
        self.close_tab();
2✔
103
        self.selected = self.previously_selected;
2✔
104
    }
2✔
105

106
    /// ### is_tab_open
107
    ///
108
    /// Returns whether the tab is open
109
    #[must_use]
110
    pub fn is_tab_open(&self) -> bool {
46✔
111
        self.tab_open
46✔
112
    }
46✔
113
}
114

115
// -- component
116

117
#[derive(Default)]
118
#[must_use]
119
pub struct Select {
120
    props: Props,
121
    pub states: SelectStates,
122
}
123

124
impl Select {
125
    pub fn foreground(mut self, fg: Color) -> Self {
2✔
126
        self.attr(Attribute::Foreground, AttrValue::Color(fg));
2✔
127
        self
2✔
128
    }
2✔
129

130
    pub fn background(mut self, bg: Color) -> Self {
2✔
131
        self.attr(Attribute::Background, AttrValue::Color(bg));
2✔
132
        self
2✔
133
    }
2✔
134

135
    pub fn borders(mut self, b: Borders) -> Self {
2✔
136
        self.attr(Attribute::Borders, AttrValue::Borders(b));
2✔
137
        self
2✔
138
    }
2✔
139

140
    pub fn title<T: Into<Title>>(mut self, title: T) -> Self {
2✔
141
        self.attr(Attribute::Title, AttrValue::Title(title.into()));
2✔
142
        self
2✔
143
    }
2✔
144

145
    pub fn highlighted_str<S: Into<LineStatic>>(mut self, s: S) -> Self {
2✔
146
        self.attr(Attribute::HighlightedStr, AttrValue::TextLine(s.into()));
2✔
147
        self
2✔
148
    }
2✔
149

150
    pub fn highlighted_color(mut self, c: Color) -> Self {
2✔
151
        self.attr(Attribute::HighlightedColor, AttrValue::Color(c));
2✔
152
        self
2✔
153
    }
2✔
154

155
    pub fn inactive(mut self, s: Style) -> Self {
×
156
        self.attr(Attribute::FocusStyle, AttrValue::Style(s));
×
157
        self
×
158
    }
×
159

160
    pub fn rewind(mut self, r: bool) -> Self {
2✔
161
        self.attr(Attribute::Rewind, AttrValue::Flag(r));
2✔
162
        self
2✔
163
    }
2✔
164

165
    pub fn choices<S: Into<String>>(mut self, choices: impl IntoIterator<Item = S>) -> Self {
14✔
166
        self.attr(
14✔
167
            Attribute::Content,
14✔
168
            AttrValue::Payload(PropPayload::Vec(
7✔
169
                choices
14✔
170
                    .into_iter()
14✔
171
                    .map(|v| PropValue::Str(v.into()))
18✔
172
                    .collect(),
14✔
173
            )),
7✔
174
        );
7✔
175
        self
14✔
176
    }
14✔
177

178
    pub fn value(mut self, i: usize) -> Self {
2✔
179
        // Set state
1✔
180
        self.attr(
2✔
181
            Attribute::Value,
2✔
182
            AttrValue::Payload(PropPayload::One(PropValue::Usize(i))),
2✔
183
        );
1✔
184
        self
2✔
185
    }
2✔
186

187
    /// ### render_open_tab
188
    ///
189
    /// Render component when tab is open
190
    fn render_open_tab(&mut self, render: &mut Frame, area: Rect) {
×
191
        // Make choices
192
        let choices: Vec<ListItem> = self
×
193
            .states
×
194
            .choices
×
195
            .iter()
×
196
            .map(|x| ListItem::new(Spans::from(x.as_str())))
×
197
            .collect();
×
198
        let foreground = self
×
199
            .props
×
200
            .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
×
201
            .unwrap_color();
×
202
        let background = self
×
203
            .props
×
204
            .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
×
205
            .unwrap_color();
×
206
        let hg: Color = self
×
207
            .props
×
208
            .get_or(Attribute::HighlightedColor, AttrValue::Color(foreground))
×
209
            .unwrap_color();
×
210
        // Prepare layout
211
        let chunks = Layout::default()
×
212
            .direction(LayoutDirection::Vertical)
×
213
            .margin(0)
×
214
            .constraints([Constraint::Length(2), Constraint::Min(1)])
×
215
            .split(area);
×
216
        // Render like "closed" tab in chunk 0
217
        let selected_text: String = match self.states.choices.get(self.states.selected) {
×
218
            None => String::default(),
×
219
            Some(s) => s.clone(),
×
220
        };
221
        let focus = self
×
222
            .props
×
223
            .get_or(Attribute::Focus, AttrValue::Flag(false))
×
224
            .unwrap_flag();
×
225
        let inactive_style = self
×
226
            .props
×
227
            .get(Attribute::FocusStyle)
×
228
            .map(|x| x.unwrap_style());
×
229

230
        let normal_style = Style::default().bg(background).fg(foreground);
×
231

232
        let borders = self
×
233
            .props
×
234
            .get_or(Attribute::Borders, AttrValue::Borders(Borders::default()))
×
235
            .unwrap_borders();
×
236
        let title = self
×
237
            .props
×
238
            .get_ref(Attribute::Title)
×
239
            .and_then(|x| x.as_title());
×
240
        let block_a = crate::utils::get_block(borders, title, focus, inactive_style)
×
241
            .borders(BorderSides::LEFT | BorderSides::TOP | BorderSides::RIGHT);
×
242
        let block_b = crate::utils::get_block(borders, None, focus, inactive_style)
×
243
            .borders(BorderSides::LEFT | BorderSides::BOTTOM | BorderSides::RIGHT);
×
244

245
        let p: Paragraph = Paragraph::new(selected_text)
×
246
            .style(normal_style)
×
247
            .block(block_a);
×
248
        render.render_widget(p, chunks[0]);
×
249

250
        // Render the list of elements in chunks [1]
251
        // Make list
252
        let mut list = List::new(choices)
×
253
            .block(block_b)
×
254
            .direction(tuirealm::ratatui::widgets::ListDirection::TopToBottom)
×
255
            .style(normal_style)
×
256
            .highlight_style(
×
257
                Style::default()
×
258
                    .fg(hg)
×
259
                    .add_modifier(TextModifiers::REVERSED),
×
260
            );
261
        // Highlighted symbol
262
        let hg_str = self
×
263
            .props
×
264
            .get_ref(Attribute::HighlightedStr)
×
NEW
265
            .and_then(|x| x.as_textline());
×
266
        if let Some(hg_str) = hg_str {
×
NEW
267
            list = list.highlight_symbol(borrow_clone_line(hg_str));
×
268
        }
×
269
        let mut state: ListState = ListState::default();
×
270
        state.select(Some(self.states.selected));
×
271
        render.render_stateful_widget(list, chunks[1], &mut state);
×
272
    }
×
273

274
    /// ### render_closed_tab
275
    ///
276
    /// Render component when tab is closed
277
    fn render_closed_tab(&self, render: &mut Frame, area: Rect) {
×
278
        let foreground = self
×
279
            .props
×
280
            .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
×
281
            .unwrap_color();
×
282
        let background = self
×
283
            .props
×
284
            .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
×
285
            .unwrap_color();
×
286
        let inactive_style = self
×
287
            .props
×
288
            .get(Attribute::FocusStyle)
×
289
            .map(|x| x.unwrap_style());
×
290
        let focus = self
×
291
            .props
×
292
            .get_or(Attribute::Focus, AttrValue::Flag(false))
×
293
            .unwrap_flag();
×
294

295
        let normal_style = Style::default().bg(background).fg(foreground);
×
296

297
        let borders = self
×
298
            .props
×
299
            .get_or(Attribute::Borders, AttrValue::Borders(Borders::default()))
×
300
            .unwrap_borders();
×
301
        let title = self
×
302
            .props
×
303
            .get_ref(Attribute::Title)
×
304
            .and_then(|x| x.as_title());
×
305
        let block = crate::utils::get_block(borders, title, focus, inactive_style);
×
306

307
        let selected_text: String = match self.states.choices.get(self.states.selected) {
×
308
            None => String::default(),
×
309
            Some(s) => s.clone(),
×
310
        };
311
        let p: Paragraph = Paragraph::new(selected_text)
×
312
            .style(normal_style)
×
313
            .block(block);
×
314
        render.render_widget(p, area);
×
315
    }
×
316

317
    fn rewindable(&self) -> bool {
16✔
318
        self.props
16✔
319
            .get_or(Attribute::Rewind, AttrValue::Flag(false))
16✔
320
            .unwrap_flag()
16✔
321
    }
16✔
322
}
323

324
impl MockComponent for Select {
325
    fn view(&mut self, render: &mut Frame, area: Rect) {
×
326
        if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
×
327
            if self.states.is_tab_open() {
×
328
                self.render_open_tab(render, area);
×
329
            } else {
×
330
                self.render_closed_tab(render, area);
×
331
            }
×
332
        }
×
333
    }
×
334

335
    fn query(&self, attr: Attribute) -> Option<AttrValue> {
×
336
        self.props.get(attr)
×
337
    }
×
338

339
    fn attr(&mut self, attr: Attribute, value: AttrValue) {
32✔
340
        match attr {
×
341
            Attribute::Content => {
7✔
342
                // Reset choices
7✔
343
                let choices: Vec<String> = value
14✔
344
                    .unwrap_payload()
14✔
345
                    .unwrap_vec()
14✔
346
                    .iter()
14✔
347
                    .map(|x| x.clone().unwrap_str())
18✔
348
                    .collect();
14✔
349
                self.states.set_choices(choices);
14✔
350
            }
7✔
351
            Attribute::Value => {
4✔
352
                self.states
4✔
353
                    .select(value.unwrap_payload().unwrap_one().unwrap_usize());
4✔
354
            }
4✔
355
            Attribute::Focus if self.states.is_tab_open() => {
×
356
                if let AttrValue::Flag(false) = value {
×
357
                    self.states.cancel_tab();
×
358
                }
×
359
                self.props.set(attr, value);
×
360
            }
361
            attr => {
14✔
362
                self.props.set(attr, value);
14✔
363
            }
14✔
364
        }
365
    }
32✔
366

367
    fn state(&self) -> State {
6✔
368
        if self.states.is_tab_open() {
6✔
369
            State::None
×
370
        } else {
371
            State::One(StateValue::Usize(self.states.selected))
6✔
372
        }
373
    }
6✔
374

375
    fn perform(&mut self, cmd: Cmd) -> CmdResult {
22✔
376
        match cmd {
16✔
377
            Cmd::Move(Direction::Down) => {
378
                // Increment choice
379
                self.states.next_choice(self.rewindable());
8✔
380
                // Return CmdResult On Change or None if tab is closed
4✔
381
                if self.states.is_tab_open() {
8✔
382
                    CmdResult::Changed(State::One(StateValue::Usize(self.states.selected)))
6✔
383
                } else {
384
                    CmdResult::None
2✔
385
                }
386
            }
387
            Cmd::Move(Direction::Up) => {
388
                // Increment choice
389
                self.states.prev_choice(self.rewindable());
8✔
390
                // Return CmdResult On Change or None if tab is closed
4✔
391
                if self.states.is_tab_open() {
8✔
392
                    CmdResult::Changed(State::One(StateValue::Usize(self.states.selected)))
6✔
393
                } else {
394
                    CmdResult::None
2✔
395
                }
396
            }
397
            Cmd::Cancel => {
398
                self.states.cancel_tab();
×
399
                CmdResult::Changed(self.state())
×
400
            }
401
            Cmd::Submit => {
402
                // Open or close tab
403
                if self.states.is_tab_open() {
6✔
404
                    self.states.close_tab();
4✔
405
                    CmdResult::Submit(self.state())
4✔
406
                } else {
407
                    self.states.open_tab();
2✔
408
                    CmdResult::None
2✔
409
                }
410
            }
411
            _ => CmdResult::None,
×
412
        }
413
    }
22✔
414
}
415

416
#[cfg(test)]
417
mod test {
418

419
    use super::*;
420

421
    use pretty_assertions::assert_eq;
422

423
    use tuirealm::props::{Alignment, PropPayload, PropValue};
424

425
    #[test]
426
    fn test_components_select_states() {
2✔
427
        let mut states: SelectStates = SelectStates::default();
2✔
428
        assert_eq!(states.selected, 0);
2✔
429
        assert_eq!(states.choices.len(), 0);
2✔
430
        assert_eq!(states.tab_open, false);
2✔
431
        let choices: &[String] = &[
2✔
432
            "lemon".to_string(),
2✔
433
            "strawberry".to_string(),
2✔
434
            "vanilla".to_string(),
2✔
435
            "chocolate".to_string(),
2✔
436
        ];
2✔
437
        states.set_choices(choices);
2✔
438
        assert_eq!(states.selected, 0);
2✔
439
        assert_eq!(states.choices.len(), 4);
2✔
440
        // Move
441
        states.prev_choice(false);
2✔
442
        assert_eq!(states.selected, 0);
2✔
443
        states.next_choice(false);
2✔
444
        // Tab is closed!!!
1✔
445
        assert_eq!(states.selected, 0);
2✔
446
        states.open_tab();
2✔
447
        assert_eq!(states.is_tab_open(), true);
2✔
448
        // Now we can move
449
        states.next_choice(false);
2✔
450
        assert_eq!(states.selected, 1);
2✔
451
        states.next_choice(false);
2✔
452
        assert_eq!(states.selected, 2);
2✔
453
        // Forward overflow
454
        states.next_choice(false);
2✔
455
        states.next_choice(false);
2✔
456
        assert_eq!(states.selected, 3);
2✔
457
        states.prev_choice(false);
2✔
458
        assert_eq!(states.selected, 2);
2✔
459
        // Close tab
460
        states.close_tab();
2✔
461
        assert_eq!(states.is_tab_open(), false);
2✔
462
        states.prev_choice(false);
2✔
463
        assert_eq!(states.selected, 2);
2✔
464
        // Update
465
        let choices: &[String] = &["lemon".to_string(), "strawberry".to_string()];
2✔
466
        states.set_choices(choices);
2✔
467
        assert_eq!(states.selected, 1); // Move to first index available
2✔
468
        assert_eq!(states.choices.len(), 2);
2✔
469
        let choices = vec![];
2✔
470
        states.set_choices(choices);
2✔
471
        assert_eq!(states.selected, 0); // Move to first index available
2✔
472
        assert_eq!(states.choices.len(), 0);
2✔
473
        // Rewind
474
        let choices: &[String] = &[
2✔
475
            "lemon".to_string(),
2✔
476
            "strawberry".to_string(),
2✔
477
            "vanilla".to_string(),
2✔
478
            "chocolate".to_string(),
2✔
479
        ];
2✔
480
        states.set_choices(choices);
2✔
481
        states.open_tab();
2✔
482
        assert_eq!(states.selected, 0);
2✔
483
        states.prev_choice(true);
2✔
484
        assert_eq!(states.selected, 3);
2✔
485
        states.next_choice(true);
2✔
486
        assert_eq!(states.selected, 0);
2✔
487
        states.next_choice(true);
2✔
488
        assert_eq!(states.selected, 1);
2✔
489
        states.prev_choice(true);
2✔
490
        assert_eq!(states.selected, 0);
2✔
491
        // Cancel tab
492
        states.close_tab();
2✔
493
        states.select(2);
2✔
494
        states.open_tab();
2✔
495
        states.prev_choice(true);
2✔
496
        states.prev_choice(true);
2✔
497
        assert_eq!(states.selected, 0);
2✔
498
        states.cancel_tab();
2✔
499
        assert_eq!(states.selected, 2);
2✔
500
        assert_eq!(states.is_tab_open(), false);
2✔
501
    }
2✔
502

503
    #[test]
504
    fn test_components_select() {
2✔
505
        // Make component
1✔
506
        let mut component = Select::default()
2✔
507
            .foreground(Color::Red)
2✔
508
            .background(Color::Black)
2✔
509
            .borders(Borders::default())
2✔
510
            .highlighted_color(Color::Red)
2✔
511
            .highlighted_str(">>")
2✔
512
            .title(Title::from("C'est oui ou bien c'est non?").alignment(Alignment::Center))
2✔
513
            .choices(["Oui!", "Non", "Peut-ĂȘtre"])
2✔
514
            .value(1)
2✔
515
            .rewind(false);
2✔
516
        assert_eq!(component.states.is_tab_open(), false);
2✔
517
        component.states.open_tab();
2✔
518
        assert_eq!(component.states.is_tab_open(), true);
2✔
519
        component.states.close_tab();
2✔
520
        assert_eq!(component.states.is_tab_open(), false);
2✔
521
        // Update
522
        component.attr(
2✔
523
            Attribute::Value,
2✔
524
            AttrValue::Payload(PropPayload::One(PropValue::Usize(2))),
2✔
525
        );
1✔
526
        // Get value
1✔
527
        assert_eq!(component.state(), State::One(StateValue::Usize(2)));
2✔
528
        // Open tab
529
        component.states.open_tab();
2✔
530
        // Events
1✔
531
        // Move cursor
1✔
532
        assert_eq!(
2✔
533
            component.perform(Cmd::Move(Direction::Up)),
2✔
534
            CmdResult::Changed(State::One(StateValue::Usize(1))),
1✔
535
        );
1✔
536
        assert_eq!(
2✔
537
            component.perform(Cmd::Move(Direction::Up)),
2✔
538
            CmdResult::Changed(State::One(StateValue::Usize(0))),
1✔
539
        );
1✔
540
        // Upper boundary
541
        assert_eq!(
2✔
542
            component.perform(Cmd::Move(Direction::Up)),
2✔
543
            CmdResult::Changed(State::One(StateValue::Usize(0))),
1✔
544
        );
1✔
545
        // Move down
546
        assert_eq!(
2✔
547
            component.perform(Cmd::Move(Direction::Down)),
2✔
548
            CmdResult::Changed(State::One(StateValue::Usize(1))),
1✔
549
        );
1✔
550
        assert_eq!(
2✔
551
            component.perform(Cmd::Move(Direction::Down)),
2✔
552
            CmdResult::Changed(State::One(StateValue::Usize(2))),
1✔
553
        );
1✔
554
        // Lower boundary
555
        assert_eq!(
2✔
556
            component.perform(Cmd::Move(Direction::Down)),
2✔
557
            CmdResult::Changed(State::One(StateValue::Usize(2))),
1✔
558
        );
1✔
559
        // Press enter
560
        assert_eq!(
2✔
561
            component.perform(Cmd::Submit),
2✔
562
            CmdResult::Submit(State::One(StateValue::Usize(2))),
1✔
563
        );
1✔
564
        // Tab should be closed
565
        assert_eq!(component.states.is_tab_open(), false);
2✔
566
        // Re open
567
        assert_eq!(component.perform(Cmd::Submit), CmdResult::None);
2✔
568
        assert_eq!(component.states.is_tab_open(), true);
2✔
569
        // Move arrows
570
        assert_eq!(
2✔
571
            component.perform(Cmd::Submit),
2✔
572
            CmdResult::Submit(State::One(StateValue::Usize(2))),
1✔
573
        );
1✔
574
        assert_eq!(component.states.is_tab_open(), false);
2✔
575
        assert_eq!(
2✔
576
            component.perform(Cmd::Move(Direction::Down)),
2✔
577
            CmdResult::None
1✔
578
        );
1✔
579
        assert_eq!(component.perform(Cmd::Move(Direction::Up)), CmdResult::None);
2✔
580
    }
2✔
581

582
    #[test]
583
    fn various_set_choice_types() {
2✔
584
        // static array of strings
1✔
585
        SelectStates::default().set_choices(&["hello".to_string()]);
2✔
586
        // vector of strings
1✔
587
        SelectStates::default().set_choices(vec!["hello".to_string()]);
2✔
588
        // boxed array of strings
1✔
589
        SelectStates::default().set_choices(vec!["hello".to_string()].into_boxed_slice());
2✔
590
    }
2✔
591

592
    #[test]
593
    fn various_choice_types() {
2✔
594
        // static array of static strings
1✔
595
        let _ = Select::default().choices(["hello"]);
2✔
596
        // static array of strings
1✔
597
        let _ = Select::default().choices(["hello".to_string()]);
2✔
598
        // vec of static strings
1✔
599
        let _ = Select::default().choices(vec!["hello"]);
2✔
600
        // vec of strings
1✔
601
        let _ = Select::default().choices(vec!["hello".to_string()]);
2✔
602
        // boxed array of static strings
1✔
603
        let _ = Select::default().choices(vec!["hello"].into_boxed_slice());
2✔
604
        // boxed array of strings
1✔
605
        let _ = Select::default().choices(vec!["hello".to_string()].into_boxed_slice());
2✔
606
    }
2✔
607
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc