refactor: Avoid unneeded allocations (#1345)

This commit is contained in:
Mo 2024-08-26 22:59:30 +02:00 committed by GitHub
parent e02947be61
commit 20c88aaa5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 62 additions and 108 deletions

View File

@ -14,7 +14,6 @@
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md //! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
use color_eyre::Result; use color_eyre::Result;
use itertools::Itertools;
use ratatui::{ use ratatui::{
crossterm::event::{self, Event, KeyCode, KeyEventKind}, crossterm::event::{self, Event, KeyCode, KeyEventKind},
layout::{Alignment, Constraint, Layout, Rect}, layout::{Alignment, Constraint, Layout, Rect},
@ -90,7 +89,7 @@ fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
.split(area) .split(area)
.to_vec() .to_vec()
}) })
.collect_vec(); .collect();
(title_area, main_areas) (title_area, main_areas)
} }

View File

@ -99,19 +99,16 @@ fn render_fg_named_colors(frame: &mut Frame, bg: Color, area: Rect) {
let inner = block.inner(area); let inner = block.inner(area);
frame.render_widget(block, area); frame.render_widget(block, area);
let layout = Layout::vertical([Constraint::Length(1); 2]) let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
.split(inner) let areas = vertical.iter().flat_map(|area| {
.iter() Layout::horizontal([Constraint::Ratio(1, 8); 8])
.flat_map(|area| { .split(*area)
Layout::horizontal([Constraint::Ratio(1, 8); 8]) .to_vec()
.split(*area) });
.to_vec() for (fg, area) in NAMED_COLORS.into_iter().zip(areas) {
})
.collect_vec();
for (i, &fg) in NAMED_COLORS.iter().enumerate() {
let color_name = fg.to_string(); let color_name = fg.to_string();
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg); let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
frame.render_widget(paragraph, layout[i]); frame.render_widget(paragraph, area);
} }
} }
@ -120,19 +117,16 @@ fn render_bg_named_colors(frame: &mut Frame, fg: Color, area: Rect) {
let inner = block.inner(area); let inner = block.inner(area);
frame.render_widget(block, area); frame.render_widget(block, area);
let layout = Layout::vertical([Constraint::Length(1); 2]) let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
.split(inner) let areas = vertical.iter().flat_map(|area| {
.iter() Layout::horizontal([Constraint::Ratio(1, 8); 8])
.flat_map(|area| { .split(*area)
Layout::horizontal([Constraint::Ratio(1, 8); 8]) .to_vec()
.split(*area) });
.to_vec() for (bg, area) in NAMED_COLORS.into_iter().zip(areas) {
})
.collect_vec();
for (i, &bg) in NAMED_COLORS.iter().enumerate() {
let color_name = bg.to_string(); let color_name = bg.to_string();
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg); let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
frame.render_widget(paragraph, layout[i]); frame.render_widget(paragraph, area);
} }
} }

View File

@ -346,13 +346,8 @@ impl App {
} }
fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) { fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
let blocks = Layout::horizontal( let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
self.constraints let blocks = Layout::horizontal(constraints).split(area);
.iter()
.map(|_| Constraint::Fill(1))
.collect_vec(),
)
.split(area);
for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() { for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
let selected = self.selected_index == i; let selected = self.selected_index == i;

View File

@ -96,13 +96,10 @@ fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
.map(|e| e.from.width()) .map(|e| e.from.width())
.max() .max()
.unwrap_or_default(); .unwrap_or_default();
let items = EMAILS let items = EMAILS.iter().map(|e| {
.iter() let from = format!("{:width$}", e.from, width = from_width).into();
.map(|e| { ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
let from = format!("{:width$}", e.from, width = from_width).into(); });
ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
})
.collect_vec();
let mut state = ListState::default().with_selected(Some(selected_index)); let mut state = ListState::default().with_selected(Some(selected_index));
StatefulWidget::render( StatefulWidget::render(
List::new(items) List::new(items)

View File

@ -52,10 +52,7 @@ impl Widget for TracerouteTab {
fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) { fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) {
let mut state = TableState::default().with_selected(Some(selected_row)); let mut state = TableState::default().with_selected(Some(selected_row));
let rows = HOPS let rows = HOPS.iter().map(|hop| Row::new(vec![hop.host, hop.address]));
.iter()
.map(|hop| Row::new(vec![hop.host, hop.address]))
.collect_vec();
let block = Block::new() let block = Block::new()
.padding(Padding::new(1, 1, 1, 1)) .padding(Padding::new(1, 1, 1, 1))
.title_alignment(Alignment::Center) .title_alignment(Alignment::Center)

View File

@ -74,31 +74,28 @@ fn draw(frame: &mut Frame) {
Min(0), // fills remaining space Min(0), // fills remaining space
]) ])
.split(examples_area); .split(examples_area);
let example_areas = example_rows let example_areas = example_rows.iter().flat_map(|area| {
Layout::horizontal([
Length(14),
Length(14),
Length(14),
Length(14),
Length(14),
Min(0), // fills remaining space
])
.split(*area)
.iter() .iter()
.flat_map(|area| { .copied()
Layout::horizontal([ .take(5) // ignore Min(0)
Length(14), .collect_vec()
Length(14), });
Length(14),
Length(14),
Length(14),
Min(0), // fills remaining space
])
.split(*area)
.iter()
.copied()
.take(5) // ignore Min(0)
.collect_vec()
})
.collect_vec();
// the examples are a cartesian product of the following constraints // the examples are a cartesian product of the following constraints
// e.g. Len/Len, Len/Min, Len/Max, Len/Perc, Len/Ratio, Min/Len, Min/Min, ... // e.g. Len/Len, Len/Min, Len/Max, Len/Perc, Len/Ratio, Min/Len, Min/Min, ...
let examples = [ let examples = [
( (
"Len", "Len",
vec![ [
Length(0), Length(0),
Length(2), Length(2),
Length(3), Length(3),
@ -107,17 +104,11 @@ fn draw(frame: &mut Frame) {
Length(15), Length(15),
], ],
), ),
( ("Min", [Min(0), Min(2), Min(3), Min(6), Min(10), Min(15)]),
"Min", ("Max", [Max(0), Max(2), Max(3), Max(6), Max(10), Max(15)]),
vec![Min(0), Min(2), Min(3), Min(6), Min(10), Min(15)],
),
(
"Max",
vec![Max(0), Max(2), Max(3), Max(6), Max(10), Max(15)],
),
( (
"Perc", "Perc",
vec![ [
Percentage(0), Percentage(0),
Percentage(25), Percentage(25),
Percentage(50), Percentage(50),
@ -128,7 +119,7 @@ fn draw(frame: &mut Frame) {
), ),
( (
"Ratio", "Ratio",
vec![ [
Ratio(0, 4), Ratio(0, 4),
Ratio(1, 4), Ratio(1, 4),
Ratio(2, 4), Ratio(2, 4),
@ -139,24 +130,15 @@ fn draw(frame: &mut Frame) {
), ),
]; ];
for (i, (a, b)) in examples for ((a, b), area) in examples
.iter() .iter()
.cartesian_product(examples.iter()) .cartesian_product(examples.iter())
.enumerate() .zip(example_areas)
{ {
let (name_a, examples_a) = a; let (name_a, examples_a) = a;
let (name_b, examples_b) = b; let (name_b, examples_b) = b;
let constraints = examples_a let constraints = examples_a.iter().copied().zip(examples_b.iter().copied());
.iter() render_example_combination(frame, area, &format!("{name_a}/{name_b}"), constraints);
.copied()
.zip(examples_b.iter().copied())
.collect_vec();
render_example_combination(
frame,
example_areas[i],
&format!("{name_a}/{name_b}"),
constraints,
);
} }
} }
@ -165,7 +147,7 @@ fn render_example_combination(
frame: &mut Frame, frame: &mut Frame,
area: Rect, area: Rect,
title: &str, title: &str,
constraints: Vec<(Constraint, Constraint)>, constraints: impl ExactSizeIterator<Item = (Constraint, Constraint)>,
) { ) {
let block = Block::bordered() let block = Block::bordered()
.title(title.gray()) .title(title.gray())
@ -174,8 +156,8 @@ fn render_example_combination(
let inner = block.inner(area); let inner = block.inner(area);
frame.render_widget(block, area); frame.render_widget(block, area);
let layout = Layout::vertical(vec![Length(1); constraints.len() + 1]).split(inner); let layout = Layout::vertical(vec![Length(1); constraints.len() + 1]).split(inner);
for (i, (a, b)) in constraints.into_iter().enumerate() { for ((a, b), &area) in constraints.into_iter().zip(layout.iter()) {
render_single_example(frame, layout[i], vec![a, b, Min(0)]); render_single_example(frame, area, vec![a, b, Min(0)]);
} }
// This is to make it easy to visually see the alignment of the examples // This is to make it easy to visually see the alignment of the examples
// with the constraints. // with the constraints.

View File

@ -294,7 +294,7 @@ fn generate_fake_names() -> Vec<Data> {
} }
}) })
.sorted_by(|a, b| a.name.cmp(&b.name)) .sorted_by(|a, b| a.name.cmp(&b.name))
.collect_vec() .collect()
} }
fn constraint_len_calculator(items: &[Data]) -> (u16, u16, u16) { fn constraint_len_calculator(items: &[Data]) -> (u16, u16, u16) {

View File

@ -1,6 +1,5 @@
use std::fmt; use std::fmt;
use itertools::Itertools;
use strum::EnumIs; use strum::EnumIs;
/// A constraint that defines the size of a layout element. /// A constraint that defines the size of a layout element.
@ -229,7 +228,7 @@ impl Constraint {
where where
T: IntoIterator<Item = u16>, T: IntoIterator<Item = u16>,
{ {
lengths.into_iter().map(Self::Length).collect_vec() lengths.into_iter().map(Self::Length).collect()
} }
/// Convert an iterator of ratios into a vector of constraints /// Convert an iterator of ratios into a vector of constraints
@ -246,10 +245,7 @@ impl Constraint {
where where
T: IntoIterator<Item = (u32, u32)>, T: IntoIterator<Item = (u32, u32)>,
{ {
ratios ratios.into_iter().map(|(n, d)| Self::Ratio(n, d)).collect()
.into_iter()
.map(|(n, d)| Self::Ratio(n, d))
.collect_vec()
} }
/// Convert an iterator of percentages into a vector of constraints /// Convert an iterator of percentages into a vector of constraints
@ -266,7 +262,7 @@ impl Constraint {
where where
T: IntoIterator<Item = u16>, T: IntoIterator<Item = u16>,
{ {
percentages.into_iter().map(Self::Percentage).collect_vec() percentages.into_iter().map(Self::Percentage).collect()
} }
/// Convert an iterator of maxes into a vector of constraints /// Convert an iterator of maxes into a vector of constraints
@ -283,7 +279,7 @@ impl Constraint {
where where
T: IntoIterator<Item = u16>, T: IntoIterator<Item = u16>,
{ {
maxes.into_iter().map(Self::Max).collect_vec() maxes.into_iter().map(Self::Max).collect()
} }
/// Convert an iterator of mins into a vector of constraints /// Convert an iterator of mins into a vector of constraints
@ -300,7 +296,7 @@ impl Constraint {
where where
T: IntoIterator<Item = u16>, T: IntoIterator<Item = u16>,
{ {
mins.into_iter().map(Self::Min).collect_vec() mins.into_iter().map(Self::Min).collect()
} }
/// Convert an iterator of proportional factors into a vector of constraints /// Convert an iterator of proportional factors into a vector of constraints
@ -317,10 +313,7 @@ impl Constraint {
where where
T: IntoIterator<Item = u16>, T: IntoIterator<Item = u16>,
{ {
proportional_factors proportional_factors.into_iter().map(Self::Fill).collect()
.into_iter()
.map(Self::Fill)
.collect_vec()
} }
} }

View File

@ -1315,9 +1315,9 @@ mod tests {
.flex(flex) .flex(flex)
.split(area); .split(area);
let mut buffer = Buffer::empty(area); let mut buffer = Buffer::empty(area);
for (i, c) in ('a'..='z').take(constraints.len()).enumerate() { for (c, &area) in ('a'..='z').take(constraints.len()).zip(layout.iter()) {
let s = c.to_string().repeat(area.width as usize); let s = c.to_string().repeat(area.width as usize);
Paragraph::new(s).render(layout[i], &mut buffer); Paragraph::new(s).render(area, &mut buffer);
} }
assert_eq!(buffer, Buffer::with_lines([expected])); assert_eq!(buffer, Buffer::with_lines([expected]));
} }

View File

@ -1,8 +1,6 @@
#![warn(missing_docs)] #![warn(missing_docs)]
use std::{borrow::Cow, fmt}; use std::{borrow::Cow, fmt};
use itertools::{Itertools, Position};
use crate::{prelude::*, style::Styled}; use crate::{prelude::*, style::Styled};
/// A string split over one or more lines. /// A string split over one or more lines.
@ -632,12 +630,11 @@ impl<T: fmt::Display> ToText for T {
impl fmt::Display for Text<'_> { impl fmt::Display for Text<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (position, line) in self.iter().with_position() { if let Some((last, rest)) = self.lines.split_last() {
if position == Position::Last || position == Position::Only { for line in rest {
write!(f, "{line}")?;
} else {
writeln!(f, "{line}")?; writeln!(f, "{line}")?;
} }
write!(f, "{last}")?;
} }
Ok(()) Ok(())
} }