perf: inline public getters/setters, and use non-generic inner functions
To reduce compile-times and avoid some overhead to binary size, this will modify some of our generic functions to use non-generic inner functions where possible. The inner functions are marked carefully with `#[inline(never)]` to prevent being inlined by LLVM at their callsites While looking for generic functions to optimize, I have also taken the opportunity to annotate public non-generic getters and setters with `#[inline]` to ensure that LLVM will inline them across crate boundaries. By default, only generic functions are automatically inlined, and only when enabling fat LTO are constant functions reliably inlined across crate boundaries.
This commit is contained in:
parent
c538d672df
commit
8cf372c9b9
55 changed files with 702 additions and 255 deletions
|
|
@ -32,6 +32,7 @@ where
|
|||
}
|
||||
|
||||
/// Consumes the builder and returns the model.
|
||||
#[inline]
|
||||
pub fn build(self) -> Model<SelectionMode> {
|
||||
self.0
|
||||
}
|
||||
|
|
@ -43,6 +44,7 @@ where
|
|||
{
|
||||
/// Activates the newly-inserted item.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn activate(mut self) -> Self {
|
||||
self.model.0.activate(self.id);
|
||||
self
|
||||
|
|
@ -50,6 +52,7 @@ where
|
|||
|
||||
/// Defines that the close button should appear
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn closable(mut self) -> Self {
|
||||
self.model.0.closable_set(self.id, true);
|
||||
self
|
||||
|
|
@ -60,6 +63,7 @@ where
|
|||
/// The secondary map internally uses a `Vec`, so should only be used for data that
|
||||
/// is commonly associated.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self {
|
||||
map.insert(self.id, data);
|
||||
self
|
||||
|
|
@ -69,6 +73,7 @@ where
|
|||
///
|
||||
/// Sparse maps internally use a `HashMap`, for data that is sparsely associated.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn secondary_sparse<Data>(
|
||||
self,
|
||||
map: &mut SparseSecondaryMap<Entity, Data>,
|
||||
|
|
@ -90,11 +95,13 @@ where
|
|||
/// .build()
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn data<Data: 'static>(mut self, data: Data) -> Self {
|
||||
self.model.0.data_set(self.id, data);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn divider_above(mut self) -> Self {
|
||||
self.model.0.divider_above_set(self.id, true);
|
||||
self
|
||||
|
|
@ -115,6 +122,7 @@ where
|
|||
|
||||
/// Define the position of the newly-inserted item.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn position(mut self, position: u16) -> Self {
|
||||
self.model.0.position_set(self.id, position);
|
||||
self
|
||||
|
|
@ -122,6 +130,7 @@ where
|
|||
|
||||
/// Swap the position with another item in the model.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn position_swap(mut self, other: Entity) -> Self {
|
||||
self.model.0.position_swap(self.id, other);
|
||||
self
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ where
|
|||
/// model.insert().text("Item A").activate();
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn activate(self) -> Self {
|
||||
self.model.activate(self.id);
|
||||
self
|
||||
|
|
@ -40,6 +41,7 @@ where
|
|||
/// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data"));
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn secondary<Data>(self, map: &mut SecondaryMap<Entity, Data>, data: Data) -> Self {
|
||||
map.insert(self.id, data);
|
||||
self
|
||||
|
|
@ -54,6 +56,7 @@ where
|
|||
/// model.insert().text("Item A").secondary(&mut secondary_data, String::new("custom data"));
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn secondary_sparse<Data>(
|
||||
self,
|
||||
map: &mut SparseSecondaryMap<Entity, Data>,
|
||||
|
|
@ -65,6 +68,7 @@ where
|
|||
|
||||
/// Shows a close button for this item.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn closable(self) -> Self {
|
||||
self.model.closable_set(self.id, true);
|
||||
self
|
||||
|
|
@ -78,12 +82,14 @@ where
|
|||
/// model.insert().text("Item A").data(String::from("custom string"));
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn data<Data: 'static>(self, data: Data) -> Self {
|
||||
self.model.data_set(self.id, data);
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn divider_above(self, divider_above: bool) -> Self {
|
||||
self.model.divider_above_set(self.id, divider_above);
|
||||
self
|
||||
|
|
@ -95,6 +101,7 @@ where
|
|||
/// model.insert().text("Item A").icon(IconSource::from("icon-a"));
|
||||
/// ```
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn icon(self, icon: impl Into<Icon>) -> Self {
|
||||
self.model.icon_set(self.id, icon.into());
|
||||
self
|
||||
|
|
@ -106,11 +113,13 @@ where
|
|||
/// let id = model.insert("Item A").id();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn id(self) -> Entity {
|
||||
#[inline]
|
||||
pub const fn id(self) -> Entity {
|
||||
self.id
|
||||
}
|
||||
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn indent(self, indent: u16) -> Self {
|
||||
self.model.indent_set(self.id, indent);
|
||||
self
|
||||
|
|
@ -118,6 +127,7 @@ where
|
|||
|
||||
/// Define the position of the item.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn position(self, position: u16) -> Self {
|
||||
self.model.position_set(self.id, position);
|
||||
self
|
||||
|
|
@ -125,6 +135,7 @@ where
|
|||
|
||||
/// Swap the position with another item in the model.
|
||||
#[allow(clippy::must_use_candidate, clippy::return_self_not_must_use)]
|
||||
#[inline]
|
||||
pub fn position_swap(self, other: Entity) -> Self {
|
||||
self.model.position_swap(self.id, other);
|
||||
self
|
||||
|
|
|
|||
|
|
@ -89,11 +89,13 @@ where
|
|||
/// ```ignore
|
||||
/// model.activate(id);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn activate(&mut self, id: Entity) {
|
||||
Selectable::activate(self, id);
|
||||
}
|
||||
|
||||
/// Activates the item at the given position, returning true if it was activated.
|
||||
#[inline]
|
||||
pub fn activate_position(&mut self, position: u16) -> bool {
|
||||
if let Some(entity) = self.entity_at(position) {
|
||||
self.activate(entity);
|
||||
|
|
@ -113,6 +115,7 @@ where
|
|||
/// .build();
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn builder() -> ModelBuilder<SelectionMode> {
|
||||
ModelBuilder::default()
|
||||
}
|
||||
|
|
@ -126,6 +129,7 @@ where
|
|||
/// ```ignore
|
||||
/// model.clear();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
for entity in self.order.clone() {
|
||||
self.remove(entity);
|
||||
|
|
@ -133,6 +137,7 @@ where
|
|||
}
|
||||
|
||||
/// Shows or hides the item's close button.
|
||||
#[inline]
|
||||
pub fn closable_set(&mut self, id: Entity, closable: bool) {
|
||||
if let Some(settings) = self.items.get_mut(id) {
|
||||
settings.closable = closable;
|
||||
|
|
@ -146,6 +151,7 @@ where
|
|||
/// println!("ID is still valid");
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn contains_item(&self, id: Entity) -> bool {
|
||||
self.items.contains_key(id)
|
||||
}
|
||||
|
|
@ -203,6 +209,7 @@ where
|
|||
.and_then(|storage| storage.remove(id));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn divider_above(&self, id: Entity) -> Option<bool> {
|
||||
self.divider_aboves.get(id).copied()
|
||||
}
|
||||
|
|
@ -215,6 +222,7 @@ where
|
|||
self.divider_aboves.insert(id, divider_above)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn divider_above_remove(&mut self, id: Entity) -> Option<bool> {
|
||||
self.divider_aboves.remove(id)
|
||||
}
|
||||
|
|
@ -224,6 +232,7 @@ where
|
|||
/// ```ignore
|
||||
/// model.enable(id, true);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn enable(&mut self, id: Entity, enable: bool) {
|
||||
if let Some(e) = self.items.get_mut(id) {
|
||||
e.enabled = enable;
|
||||
|
|
@ -232,6 +241,7 @@ where
|
|||
|
||||
/// Get the item that is located at a given position.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn entity_at(&mut self, position: u16) -> Option<Entity> {
|
||||
self.order.get(position as usize).copied()
|
||||
}
|
||||
|
|
@ -243,6 +253,7 @@ where
|
|||
/// println!("has icon: {:?}", icon);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn icon(&self, id: Entity) -> Option<&Icon> {
|
||||
self.icons.get(id)
|
||||
}
|
||||
|
|
@ -254,6 +265,7 @@ where
|
|||
/// println!("previously had icon: {:?}", old_icon);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn icon_set(&mut self, id: Entity, icon: Icon) -> Option<Icon> {
|
||||
if !self.contains_item(id) {
|
||||
return None;
|
||||
|
|
@ -268,6 +280,7 @@ where
|
|||
/// if let Some(old_icon) = model.icon_remove(id) {
|
||||
/// println!("previously had icon: {:?}", old_icon);
|
||||
/// }
|
||||
#[inline]
|
||||
pub fn icon_remove(&mut self, id: Entity) -> Option<Icon> {
|
||||
self.icons.remove(id)
|
||||
}
|
||||
|
|
@ -278,6 +291,7 @@ where
|
|||
/// let id = model.insert().text("Item A").icon("custom-icon").id();
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn insert(&mut self) -> EntityMut<SelectionMode> {
|
||||
let id = self.items.insert(Settings::default());
|
||||
self.order.push_back(id);
|
||||
|
|
@ -286,14 +300,16 @@ where
|
|||
|
||||
/// Check if the given ID is the active ID.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn is_active(&self, id: Entity) -> bool {
|
||||
<Self as Selectable>::is_active(self, id)
|
||||
}
|
||||
|
||||
/// Whether the item should contain a close button.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn is_closable(&self, id: Entity) -> bool {
|
||||
self.items.get(id).map_or(false, |e| e.closable)
|
||||
self.items.get(id).map(|e| e.closable).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Check if the item is enabled.
|
||||
|
|
@ -306,11 +322,13 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn is_enabled(&self, id: Entity) -> bool {
|
||||
self.items.get(id).map_or(false, |e| e.enabled)
|
||||
self.items.get(id).map(|e| e.enabled).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Get number of items in the model.
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.order.len()
|
||||
}
|
||||
|
|
@ -320,10 +338,12 @@ where
|
|||
self.order.iter().copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn indent(&self, id: Entity) -> Option<u16> {
|
||||
self.indents.get(id).copied()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn indent_set(&mut self, id: Entity, indent: u16) -> Option<u16> {
|
||||
if !self.contains_item(id) {
|
||||
return None;
|
||||
|
|
@ -332,6 +352,7 @@ where
|
|||
self.indents.insert(id, indent)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn indent_remove(&mut self, id: Entity) -> Option<u16> {
|
||||
self.indents.remove(id)
|
||||
}
|
||||
|
|
@ -343,6 +364,7 @@ where
|
|||
/// println!("found item at {}", position);
|
||||
/// }
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn position(&self, id: Entity) -> Option<u16> {
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
self.order.iter().position(|k| *k == id).map(|v| v as u16)
|
||||
|
|
@ -356,9 +378,7 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
pub fn position_set(&mut self, id: Entity, position: u16) -> Option<usize> {
|
||||
let Some(index) = self.position(id) else {
|
||||
return None;
|
||||
};
|
||||
let index = self.position(id)?;
|
||||
|
||||
self.order.remove(index as usize);
|
||||
|
||||
|
|
@ -415,6 +435,7 @@ where
|
|||
/// println!("{:?} has text {text}", id);
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn text(&self, id: Entity) -> Option<&str> {
|
||||
self.text.get(id).map(Cow::as_ref)
|
||||
}
|
||||
|
|
@ -439,6 +460,7 @@ where
|
|||
/// if let Some(old_text) = model.text_remove(id) {
|
||||
/// println!("{:?} had text {}", id, old_text);
|
||||
/// }
|
||||
#[inline]
|
||||
pub fn text_remove(&mut self, id: Entity) -> Option<Cow<'static, str>> {
|
||||
self.text.remove(id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ impl Selectable for Model<SingleSelect> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_active(&self, id: Entity) -> bool {
|
||||
self.selection.active == id
|
||||
}
|
||||
|
|
@ -47,23 +48,27 @@ impl Selectable for Model<SingleSelect> {
|
|||
impl Model<SingleSelect> {
|
||||
/// Get an immutable reference to the data associated with the active item.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn active_data<Data: 'static>(&self) -> Option<&Data> {
|
||||
self.data(self.active())
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the data associated with the active item.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn active_data_mut<Data: 'static>(&mut self) -> Option<&mut Data> {
|
||||
self.data_mut(self.active())
|
||||
}
|
||||
|
||||
/// Deactivates the active item.
|
||||
#[inline]
|
||||
pub fn deactivate(&mut self) {
|
||||
Selectable::deactivate(self, Entity::default());
|
||||
}
|
||||
|
||||
/// The ID of the active item.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn active(&self) -> Entity {
|
||||
self.selection.active
|
||||
}
|
||||
|
|
@ -86,10 +91,12 @@ impl Selectable for Model<MultiSelect> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deactivate(&mut self, id: Entity) {
|
||||
self.selection.active.remove(&id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_active(&self, id: Entity) -> bool {
|
||||
self.selection.active.contains(&id)
|
||||
}
|
||||
|
|
@ -97,11 +104,13 @@ impl Selectable for Model<MultiSelect> {
|
|||
|
||||
impl Model<MultiSelect> {
|
||||
/// Deactivates the item in the model.
|
||||
#[inline]
|
||||
pub fn deactivate(&mut self, id: Entity) {
|
||||
Selectable::deactivate(self, id);
|
||||
}
|
||||
|
||||
/// The IDs of the active items.
|
||||
#[inline]
|
||||
pub fn active(&self) -> impl Iterator<Item = Entity> + '_ {
|
||||
self.selection.active.iter().copied()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ use iced::{
|
|||
event, keyboard, mouse, touch,
|
||||
};
|
||||
use iced_core::mouse::ScrollDelta;
|
||||
use iced_core::text::{LineHeight, Paragraph, Renderer as TextRenderer, Shaping, Wrapping};
|
||||
use iced_core::text::{LineHeight, Renderer as TextRenderer, Shaping, Wrapping};
|
||||
use iced_core::widget::{self, operation, tree};
|
||||
use iced_core::{Border, Gradient, Point, Renderer as IcedRenderer, Shadow, Text};
|
||||
use iced_core::{Clipboard, Layout, Shell, Widget, layout, renderer, widget::Tree};
|
||||
|
|
@ -158,6 +158,7 @@ where
|
|||
Model<SelectionMode>: Selectable,
|
||||
SelectionMode: Default,
|
||||
{
|
||||
#[inline]
|
||||
pub fn new(model: &'a Model<SelectionMode>) -> Self {
|
||||
Self {
|
||||
model,
|
||||
|
|
@ -1726,6 +1727,7 @@ impl Id {
|
|||
///
|
||||
/// This function produces a different [`Id`] every time it is called.
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn unique() -> Self {
|
||||
Self(widget::Id::unique())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue