Reduce monomorphization, reducing wasm size by around 3%

This commit is contained in:
Emil Ernerfeldt 2021-09-07 21:33:10 +02:00
parent bb034e2e6c
commit 241667b078
11 changed files with 154 additions and 40 deletions

View File

@ -347,10 +347,19 @@ impl CollapsingHeader {
}
}
#[inline]
pub fn show<R>(
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> CollapsingResponse<R> {
self.show_dyn(ui, Box::new(add_contents))
}
fn show_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> CollapsingResponse<R> {
// Make sure contents are bellow header,
// and make sure it is one unit (necessary for putting a `CollapsingHeader` in a grid).

View File

@ -69,6 +69,14 @@ impl ComboBox {
self,
ui: &mut Ui,
menu_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<Option<R>> {
self.show_ui_dyn(ui, Box::new(menu_contents))
}
fn show_ui_dyn<'c, R>(
self,
ui: &mut Ui,
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<Option<R>> {
let Self {
id_source,
@ -83,7 +91,7 @@ impl ComboBox {
if let Some(width) = width {
ui.spacing_mut().slider_width = width; // yes, this is ugly. Will remove later.
}
let mut ir = combo_box(ui, button_id, selected_text, menu_contents);
let mut ir = combo_box_dyn(ui, button_id, selected_text, menu_contents);
if let Some(label) = label {
ir.response
.widget_info(|| WidgetInfo::labeled(WidgetType::ComboBox, label.text()));
@ -144,11 +152,11 @@ impl ComboBox {
}
#[allow(clippy::needless_pass_by_value)]
fn combo_box<R>(
fn combo_box_dyn<'c, R>(
ui: &mut Ui,
button_id: Id,
selected: impl ToString,
menu_contents: impl FnOnce(&mut Ui) -> R,
menu_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<Option<R>> {
let popup_id = button_id.with("popup");

View File

@ -155,6 +155,14 @@ impl Frame {
}
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
self.show_dyn(ui, Box::new(add_contents))
}
fn show_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let mut prepared = self.begin(ui);
let ret = add_contents(&mut prepared.content_ui);
let response = prepared.end(ui);

View File

@ -147,6 +147,15 @@ impl SidePanel {
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_inside_dyn(ui, Box::new(add_contents))
}
/// Show the panel inside a `Ui`.
fn show_inside_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let Self {
side,
@ -259,6 +268,15 @@ impl SidePanel {
self,
ctx: &CtxRef,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_dyn(ctx, Box::new(add_contents))
}
/// Show the panel at the top level.
fn show_dyn<'c, R>(
self,
ctx: &CtxRef,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let layer_id = LayerId::background();
let side = self.side;
@ -266,7 +284,7 @@ impl SidePanel {
let clip_rect = ctx.input().screen_rect();
let mut panel_ui = Ui::new(ctx.clone(), layer_id, self.id, available_rect, clip_rect);
let inner_response = self.show_inside(&mut panel_ui, add_contents);
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
let rect = inner_response.response.rect;
match side {
@ -406,6 +424,15 @@ impl TopBottomPanel {
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_inside_dyn(ui, Box::new(add_contents))
}
/// Show the panel inside a `Ui`.
fn show_inside_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let Self {
side,
@ -520,6 +547,15 @@ impl TopBottomPanel {
self,
ctx: &CtxRef,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_dyn(ctx, Box::new(add_contents))
}
/// Show the panel at the top level.
fn show_dyn<'c, R>(
self,
ctx: &CtxRef,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let layer_id = LayerId::background();
let available_rect = ctx.available_rect();
@ -528,7 +564,7 @@ impl TopBottomPanel {
let clip_rect = ctx.input().screen_rect();
let mut panel_ui = Ui::new(ctx.clone(), layer_id, self.id, available_rect, clip_rect);
let inner_response = self.show_inside(&mut panel_ui, add_contents);
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
let rect = inner_response.response.rect;
match side {
@ -585,6 +621,15 @@ impl CentralPanel {
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_inside_dyn(ui, Box::new(add_contents))
}
/// Show the panel inside a `Ui`.
fn show_inside_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let Self { frame } = self;
@ -603,6 +648,15 @@ impl CentralPanel {
self,
ctx: &CtxRef,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.show_dyn(ctx, Box::new(add_contents))
}
/// Show the panel at the top level.
fn show_dyn<'c, R>(
self,
ctx: &CtxRef,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let available_rect = ctx.available_rect();
let layer_id = LayerId::background();
@ -611,7 +665,7 @@ impl CentralPanel {
let clip_rect = ctx.input().screen_rect();
let mut panel_ui = Ui::new(ctx.clone(), layer_id, id, available_rect, clip_rect);
let inner_response = self.show_inside(&mut panel_ui, add_contents);
let inner_response = self.show_inside_dyn(&mut panel_ui, add_contents);
// Only inform ctx about what we actually used, so we can shrink the native window to fit.
ctx.frame_state()

View File

@ -100,12 +100,12 @@ pub fn show_tooltip_under<R>(
add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<R> {
let expanded_rect = rect.expand2(vec2(2.0, 4.0));
show_tooltip_at_avoid(
show_tooltip_at_avoid_dyn(
ctx,
id,
Some(expanded_rect.left_bottom()),
expanded_rect,
add_contents,
Box::new(add_contents),
)
}
@ -118,15 +118,21 @@ pub fn show_tooltip_at<R>(
suggested_position: Option<Pos2>,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<R> {
show_tooltip_at_avoid(ctx, id, suggested_position, Rect::NOTHING, add_contents)
show_tooltip_at_avoid_dyn(
ctx,
id,
suggested_position,
Rect::NOTHING,
Box::new(add_contents),
)
}
fn show_tooltip_at_avoid<R>(
fn show_tooltip_at_avoid_dyn<'c, R>(
ctx: &CtxRef,
mut id: Id,
suggested_position: Option<Pos2>,
mut avoid_rect: Rect,
add_contents: impl FnOnce(&mut Ui) -> R,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> Option<R> {
let mut tooltip_rect = Rect::NOTHING;
let mut count = 0;
@ -170,7 +176,7 @@ fn show_tooltip_at_avoid<R>(
let position = position.max(ctx.input().screen_rect().left_top());
let InnerResponse { inner, response } = show_tooltip_area(ctx, id, position, add_contents);
let InnerResponse { inner, response } = show_tooltip_area_dyn(ctx, id, position, add_contents);
ctx.memory()
.data_temp
.get_mut_or_default::<crate::containers::popup::MonoState>()
@ -201,11 +207,11 @@ pub fn show_tooltip_text(ctx: &CtxRef, id: Id, text: impl ToString) -> Option<()
}
/// Show a pop-over window.
fn show_tooltip_area<R>(
fn show_tooltip_area_dyn<'c, R>(
ctx: &CtxRef,
id: Id,
window_pos: Pos2,
add_contents: impl FnOnce(&mut Ui) -> R,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
use containers::*;
Area::new(id)

View File

@ -304,7 +304,7 @@ impl ScrollArea {
///
/// If the inner area can be very long, consider using [`Self::show_rows`] instead.
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> R {
self.show_viewport(ui, |ui, _viewport| add_contents(ui))
self.show_viewport_dyn(ui, Box::new(|ui, _viewport| add_contents(ui)))
}
/// Efficiently show only the visible part of a large number of rows.
@ -357,6 +357,14 @@ impl ScrollArea {
/// `add_contents` is past the viewport, which is the relative view of the content.
/// So if the passed rect has min = zero, then show the top left content (the user has not scrolled).
pub fn show_viewport<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui, Rect) -> R) -> R {
self.show_viewport_dyn(ui, Box::new(add_contents))
}
fn show_viewport_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui, Rect) -> R + 'c>,
) -> R {
let mut prepared = self.begin(ui);
let ret = add_contents(&mut prepared.content_ui, prepared.viewport);
prepared.end(ui);

View File

@ -240,15 +240,16 @@ impl<'open> Window<'open> {
impl<'open> Window<'open> {
/// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`).
/// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
#[inline]
pub fn show<R>(
self,
ctx: &CtxRef,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<InnerResponse<Option<R>>> {
self.show_impl(ctx, Box::new(add_contents))
self.show_dyn(ctx, Box::new(add_contents))
}
fn show_impl<'c, R>(
fn show_dyn<'c, R>(
self,
ctx: &CtxRef,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,

View File

@ -328,6 +328,14 @@ impl Grid {
impl Grid {
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
self.show_dyn(ui, Box::new(add_contents))
}
fn show_dyn<'c, R>(
self,
ui: &mut Ui,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let Self {
id_source,
num_columns,

View File

@ -552,6 +552,7 @@ pub struct InnerResponse<R> {
}
impl<R> InnerResponse<R> {
#[inline]
pub fn new(inner: R, response: Response) -> Self {
Self { inner, response }
}

View File

@ -1279,6 +1279,13 @@ impl Ui {
/// });
/// ```
pub fn scope<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
self.scope_dyn(Box::new(add_contents))
}
fn scope_dyn<'c, R>(
&mut self,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let child_rect = self.available_rect_before_wrap();
let next_auto_id_source = self.next_auto_id_source;
let mut child_ui = self.child_ui(child_rect, *self.layout());
@ -1391,13 +1398,12 @@ impl Ui {
/// ```
///
/// See also [`Self::with_layout`] for more options.
#[inline(always)]
#[inline]
pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
self.horizontal_with_main_wrap(false, add_contents)
self.horizontal_with_main_wrap_dyn(false, Box::new(add_contents))
}
/// Like [`Self::horizontal`], but aligns content with top.
#[inline(always)]
pub fn horizontal_top<R>(
&mut self,
add_contents: impl FnOnce(&mut Ui) -> R,
@ -1431,16 +1437,7 @@ impl Ui {
&mut self,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.horizontal_with_main_wrap(true, add_contents)
}
#[inline(always)]
fn horizontal_with_main_wrap<R>(
&mut self,
main_wrap: bool,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.horizontal_with_main_wrap_dyn(main_wrap, Box::new(add_contents))
self.horizontal_with_main_wrap_dyn(true, Box::new(add_contents))
}
fn horizontal_with_main_wrap_dyn<'c, R>(
@ -1477,7 +1474,7 @@ impl Ui {
/// See also [`Self::with_layout`] for more options.
#[inline(always)]
pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
self.with_layout(Layout::top_down(Align::Min), add_contents)
self.with_layout_dyn(Layout::top_down(Align::Min), Box::new(add_contents))
}
/// Start a ui with vertical layout.
@ -1490,11 +1487,12 @@ impl Ui {
/// ui.label("under");
/// });
/// ```
#[inline]
pub fn vertical_centered<R>(
&mut self,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.with_layout(Layout::top_down(Align::Center), add_contents)
self.with_layout_dyn(Layout::top_down(Align::Center), Box::new(add_contents))
}
/// Start a ui with vertical layout.
@ -1511,9 +1509,9 @@ impl Ui {
&mut self,
add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> {
self.with_layout(
self.with_layout_dyn(
Layout::top_down(Align::Center).with_cross_justify(true),
add_contents,
Box::new(add_contents),
)
}
@ -1529,6 +1527,7 @@ impl Ui {
///
/// See also [`Self::allocate_ui_with_layout`],
/// and the helpers [`Self::horizontal]`, [`Self::vertical`], etc.
#[inline]
pub fn with_layout<R>(
&mut self,
layout: Layout,
@ -1562,9 +1561,9 @@ impl Ui {
&mut self,
add_contents: impl FnOnce(&mut Self) -> R,
) -> InnerResponse<R> {
self.with_layout(
self.with_layout_dyn(
Layout::centered_and_justified(Direction::TopDown),
add_contents,
Box::new(add_contents),
)
}
@ -1605,10 +1604,20 @@ impl Ui {
/// columns[1].label("Second column");
/// });
/// ```
pub fn columns<F, R>(&mut self, num_columns: usize, add_contents: F) -> R
where
F: FnOnce(&mut [Self]) -> R,
{
#[inline]
pub fn columns<R>(
&mut self,
num_columns: usize,
add_contents: impl FnOnce(&mut [Self]) -> R,
) -> R {
self.columns_dyn(num_columns, Box::new(add_contents))
}
fn columns_dyn<'c, R>(
&mut self,
num_columns: usize,
add_contents: Box<dyn FnOnce(&mut [Self]) -> R + 'c>,
) -> R {
// TODO: ensure there is space
let spacing = self.spacing().item_spacing.x;
let total_spacing = spacing * (num_columns as f32 - 1.0);

View File

@ -4,3 +4,5 @@ script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
cd "$script_path/.."
cargo bloat --release --bin egui_demo_app -n 200 | rg "egui "
cargo llvm-lines -p egui_demo_lib | rg egui | head -30