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>( pub fn show<R>(
self, self,
ui: &mut Ui, ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui) -> R, 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> { ) -> CollapsingResponse<R> {
// Make sure contents are bellow header, // Make sure contents are bellow header,
// and make sure it is one unit (necessary for putting a `CollapsingHeader` in a grid). // and make sure it is one unit (necessary for putting a `CollapsingHeader` in a grid).

View File

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

View File

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

View File

@ -100,12 +100,12 @@ pub fn show_tooltip_under<R>(
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<R> { ) -> Option<R> {
let expanded_rect = rect.expand2(vec2(2.0, 4.0)); let expanded_rect = rect.expand2(vec2(2.0, 4.0));
show_tooltip_at_avoid( show_tooltip_at_avoid_dyn(
ctx, ctx,
id, id,
Some(expanded_rect.left_bottom()), Some(expanded_rect.left_bottom()),
expanded_rect, expanded_rect,
add_contents, Box::new(add_contents),
) )
} }
@ -118,15 +118,21 @@ pub fn show_tooltip_at<R>(
suggested_position: Option<Pos2>, suggested_position: Option<Pos2>,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<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, ctx: &CtxRef,
mut id: Id, mut id: Id,
suggested_position: Option<Pos2>, suggested_position: Option<Pos2>,
mut avoid_rect: Rect, mut avoid_rect: Rect,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> Option<R> { ) -> Option<R> {
let mut tooltip_rect = Rect::NOTHING; let mut tooltip_rect = Rect::NOTHING;
let mut count = 0; 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 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() ctx.memory()
.data_temp .data_temp
.get_mut_or_default::<crate::containers::popup::MonoState>() .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. /// Show a pop-over window.
fn show_tooltip_area<R>( fn show_tooltip_area_dyn<'c, R>(
ctx: &CtxRef, ctx: &CtxRef,
id: Id, id: Id,
window_pos: Pos2, window_pos: Pos2,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
use containers::*; use containers::*;
Area::new(id) 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. /// 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 { 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. /// 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. /// `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). /// 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 { 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 mut prepared = self.begin(ui);
let ret = add_contents(&mut prepared.content_ui, prepared.viewport); let ret = add_contents(&mut prepared.content_ui, prepared.viewport);
prepared.end(ui); prepared.end(ui);

View File

@ -240,15 +240,16 @@ impl<'open> Window<'open> {
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 `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. /// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
#[inline]
pub fn show<R>( pub fn show<R>(
self, self,
ctx: &CtxRef, ctx: &CtxRef,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> Option<InnerResponse<Option<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, self,
ctx: &CtxRef, ctx: &CtxRef,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>, add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,

View File

@ -328,6 +328,14 @@ impl Grid {
impl Grid { impl Grid {
pub fn show<R>(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> { 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 { let Self {
id_source, id_source,
num_columns, num_columns,

View File

@ -552,6 +552,7 @@ pub struct InnerResponse<R> {
} }
impl<R> InnerResponse<R> { impl<R> InnerResponse<R> {
#[inline]
pub fn new(inner: R, response: Response) -> Self { pub fn new(inner: R, response: Response) -> Self {
Self { inner, response } 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> { 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 child_rect = self.available_rect_before_wrap();
let next_auto_id_source = self.next_auto_id_source; let next_auto_id_source = self.next_auto_id_source;
let mut child_ui = self.child_ui(child_rect, *self.layout()); 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. /// 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> { 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. /// Like [`Self::horizontal`], but aligns content with top.
#[inline(always)]
pub fn horizontal_top<R>( pub fn horizontal_top<R>(
&mut self, &mut self,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
@ -1431,16 +1437,7 @@ impl Ui {
&mut self, &mut self,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.horizontal_with_main_wrap(true, add_contents) self.horizontal_with_main_wrap_dyn(true, Box::new(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))
} }
fn horizontal_with_main_wrap_dyn<'c, R>( fn horizontal_with_main_wrap_dyn<'c, R>(
@ -1477,7 +1474,7 @@ impl Ui {
/// See also [`Self::with_layout`] for more options. /// See also [`Self::with_layout`] for more options.
#[inline(always)] #[inline(always)]
pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> { 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. /// Start a ui with vertical layout.
@ -1490,11 +1487,12 @@ impl Ui {
/// ui.label("under"); /// ui.label("under");
/// }); /// });
/// ``` /// ```
#[inline]
pub fn vertical_centered<R>( pub fn vertical_centered<R>(
&mut self, &mut self,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<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. /// Start a ui with vertical layout.
@ -1511,9 +1509,9 @@ impl Ui {
&mut self, &mut self,
add_contents: impl FnOnce(&mut Ui) -> R, add_contents: impl FnOnce(&mut Ui) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.with_layout( self.with_layout_dyn(
Layout::top_down(Align::Center).with_cross_justify(true), 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`], /// See also [`Self::allocate_ui_with_layout`],
/// and the helpers [`Self::horizontal]`, [`Self::vertical`], etc. /// and the helpers [`Self::horizontal]`, [`Self::vertical`], etc.
#[inline]
pub fn with_layout<R>( pub fn with_layout<R>(
&mut self, &mut self,
layout: Layout, layout: Layout,
@ -1562,9 +1561,9 @@ impl Ui {
&mut self, &mut self,
add_contents: impl FnOnce(&mut Self) -> R, add_contents: impl FnOnce(&mut Self) -> R,
) -> InnerResponse<R> { ) -> InnerResponse<R> {
self.with_layout( self.with_layout_dyn(
Layout::centered_and_justified(Direction::TopDown), Layout::centered_and_justified(Direction::TopDown),
add_contents, Box::new(add_contents),
) )
} }
@ -1605,10 +1604,20 @@ impl Ui {
/// columns[1].label("Second column"); /// columns[1].label("Second column");
/// }); /// });
/// ``` /// ```
pub fn columns<F, R>(&mut self, num_columns: usize, add_contents: F) -> R #[inline]
where pub fn columns<R>(
F: FnOnce(&mut [Self]) -> 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 // TODO: ensure there is space
let spacing = self.spacing().item_spacing.x; let spacing = self.spacing().item_spacing.x;
let total_spacing = spacing * (num_columns as f32 - 1.0); 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/.." cd "$script_path/.."
cargo bloat --release --bin egui_demo_app -n 200 | rg "egui " cargo bloat --release --bin egui_demo_app -n 200 | rg "egui "
cargo llvm-lines -p egui_demo_lib | rg egui | head -30