Hi everyone !
This topic is related to my previous.
I implemented minimal sandbox similar to my origin code: Rust Playground
The issue is:
error[E0521]: borrowed data escapes outside of async block
--> src/features/ui2/mod.rs:72:37
|
41 | let mut modal = Arc::new(Mutex::new(Modal::default()));
| --------- `modal` declared here, outside of the async block body
...
72 | *modal.lock().await = Modal::default()
| ^^^^^^^^^^^^^^^^^^^ reference to `char_data` escapes the async block body here
73 | .set_title("SELECT CHARACTER")
74 | .set_items(&["Name", "Guid"], &char_data);
| ---------- borrow is only valid in the async block body
The code where I got this issue is:
Ok(input) = receiver.recv() => {
match input {
// ...
HandlerOutput::TransferCharactersList(characters) => {
let char_data = characters
.into_iter()
.flat_map(|c| vec![c.guid.to_string(), c.name])
.collect::<Vec<_>>();
*modal.lock().await = Modal::default()
.set_title("SELECT CHARACTER")
.set_items(&["Name", "Guid"], &char_data);
},
_ => {},
}
}
and my modal code is:
type NamedValue<'a> = (&'a str, &'a str);
#[derive(Default)]
pub struct Modal<'a> {
title: &'a str,
lines: Vec<Line<'a>>,
list_state: ListState,
}
impl<'a> Modal<'a> {
pub fn set_title(mut self, title: &'a str) -> Self {
self.title = title;
self
}
pub fn set_items<'b, S1, S2>(mut self, labels: &'b [S1], values: &'b [S2]) -> Self
where
S1: AsRef<str>,
S2: AsRef<str>,
{
let lines: Vec<Line> = Self::zip(&labels, &values)
.map(|row| {
let parts = row.collect::<Vec<_>>();
Self::build_line(parts)
})
.collect();
self.lines = lines;
self
}
pub fn render(&mut self, frame: &mut Frame, rect: Rect) {
let layout = &Layout::vertical(
[Constraint::Percentage(30), Constraint::Percentage(40), Constraint::Percentage(30)]
).split(rect);
let title = Line::from(
Span::raw(self.title).fg(Color::LightYellow).add_modifier(Modifier::BOLD)
);
let instructions = Line::from(vec![
Span::styled("Navigate: ", Style::new().add_modifier(Modifier::BOLD)),
Span::styled("<ArrowDn>", Style::new().fg(Color::Blue).add_modifier(Modifier::BOLD)),
Span::raw(" and "),
Span::styled("<ArrowUp>", Style::new().fg(Color::Blue).add_modifier(Modifier::BOLD)),
Span::styled(", select: ", Style::new().add_modifier(Modifier::BOLD)),
Span::styled("<Enter>", Style::new().fg(Color::Green).add_modifier(Modifier::BOLD)),
]);
let block = Block::bordered()
.title(title.centered())
.title_bottom(instructions.centered())
.border_set(border::ROUNDED);
let paragraph = Paragraph::new("").centered().block(block);
frame.render_widget(paragraph, layout[1]);
let list_items: Vec<ListItem> = self.lines
.iter()
.map(|l| ListItem::new(l.clone()))
.collect();
let list = List::new(list_items).highlight_symbol(">>>");
frame.render_stateful_widget(list, layout[1], self.list_state.borrow_mut());
}
fn build_line(parts: Vec<NamedValue>) -> Line {
let mut spans = Vec::new();
for (label, name) in parts.iter() {
spans.extend_from_slice(&[
Span::styled(
format!("{}: ", label),
Style::default().fg(Color::Magenta).add_modifier(Modifier::BOLD),
),
Span::styled(
format!("{}: ", name),
Style::default().fg(Color::Green),
)
]);
}
Line::from(spans)
}
fn zip<'b, S1, S2>(
labels: &'b [S1],
values: &'b [S2],
) -> impl Iterator<Item=impl Iterator<Item=NamedValue<'b>> + 'b>
where
S1: AsRef<str>,
S2: AsRef<str>,
{
values
.chunks(labels.len())
.map(move |chunk| {
chunk
.iter()
.zip(labels.iter())
.map(|(l, v)| (l.as_ref(), v.as_ref()))
})
}
}
I want to rid of labels
and char_data
variables, but my modal lives outside of the scope where this variables are defined.
Could somebody help me to fix the issue ?