Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ dependencies = [
"ahash",
"egui",
"enum-map",
"itertools",
"itertools 0.15.0",
"log",
"profiling",
]
Expand Down Expand Up @@ -1331,6 +1331,7 @@ dependencies = [
"emath",
"env_logger",
"log",
"nohash-hasher",
"performance_lines",
"serde",
]
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ env_logger = { version = "0.11.8", default-features = false, features = [
] }
image = { version = "0.25", default-features = false }
log = "0.4"
nohash-hasher = "0.2.0"
serde = { version = "1", features = ["derive"] }
wasm-bindgen-futures = "0.4"
web-sys = "0.3.83"
Expand Down
1 change: 1 addition & 0 deletions egui_plot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ egui = { workspace = true, default-features = false }
emath = { workspace = true, default-features = false }

ahash.workspace = true
nohash-hasher.workspace = true

#! ### Optional dependencies
## Enable this when generating docs.
Expand Down
64 changes: 64 additions & 0 deletions egui_plot/src/item_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//! Identifiers for the items within a plot.

use core::hash::Hash;
use core::num::NonZeroU64;

/// The seeds used when hashing an [`ItemId`] source.
///
/// Fixed so that the same source always produces the same [`ItemId`],
/// which is what lets [`crate::PlotMemory`] be persisted between runs.
const HASH_SEEDS: (u64, u64, u64, u64) = (9, 10, 11, 12);

/// An `ItemIdSet` is a `HashSet<ItemId>` that skips hashing,
/// since an [`ItemId`] already is a high-entropy hash.
pub type ItemIdSet = nohash_hasher::IntSet<ItemId>;

/// An `ItemIdMap<V>` is a `HashMap<ItemId, V>` that skips hashing,
/// since an [`ItemId`] already is a high-entropy hash.
pub type ItemIdMap<V> = nohash_hasher::IntMap<ItemId, V>;

/// Identifies a [`crate::PlotItem`] within a plot.
///
/// An `ItemId` only has to be unique within the plot it is used in.
///
/// By default each item derives its `ItemId` from the name it was created with,
/// but you can set one explicitly, e.g. with [`crate::Line::id`]. Do that when
/// the name changes between frames, or when several items share a name.
///
/// This is niche-optimized, so that `Option<ItemId>` is the same size as `ItemId`.
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct ItemId(NonZeroU64);

impl nohash_hasher::IsEnabled for ItemId {}

impl ItemId {
/// Hash any source (e.g. a string, an integer, or a tuple of those) into an [`ItemId`].
///
/// Prefer a tuple over formatting a string:
///
/// ```
/// # use egui_plot::ItemId;
/// # let (row, column) = (0, 0);
/// let good = ItemId::new(("my_cell", row, column)); // No allocation
/// let bad = ItemId::new(format!("my_cell {row} {column}")); // Allocates
/// # let _ = (good, bad);
/// ```
pub fn new(source: impl Hash) -> Self {
let (a, b, c, d) = HASH_SEEDS;
let hash = ahash::RandomState::with_seeds(a, b, c, d).hash_one(source);
Self(NonZeroU64::new(hash).unwrap_or(NonZeroU64::MIN)) // The hash was exactly zero (very bad luck)
}

/// The inner value, which is a high-entropy hash.
#[inline(always)]
pub fn value(self) -> u64 {
self.0.get()
}
}

impl core::fmt::Debug for ItemId {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "ItemId({:04X})", self.value() as u16)
}
}
13 changes: 8 additions & 5 deletions egui_plot/src/items/arrows.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::hash::Hash;
use std::ops::RangeInclusive;

use egui::Color32;
use egui::Id;
use egui::Shape;
use egui::Stroke;
use egui::Ui;
Expand All @@ -10,6 +10,7 @@ use emath::Rot2;
use crate::axis::PlotTransform;
use crate::bounds::PlotBounds;
use crate::data::PlotPoints;
use crate::item_id::ItemId;
use crate::items::PlotGeometry;
use crate::items::PlotItem;
use crate::items::PlotItemBase;
Expand Down Expand Up @@ -71,13 +72,15 @@ impl<'a> Arrows<'a> {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// The id only has to be unique within the plot.
///
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
13 changes: 8 additions & 5 deletions egui_plot/src/items/bar_chart.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::hash::Hash;
use std::ops::RangeInclusive;

use egui::Color32;
use egui::CornerRadius;
use egui::Id;
use egui::Shape;
use egui::Stroke;
use egui::Ui;
Expand All @@ -17,6 +17,7 @@ use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::colors::highlighted_color;
use crate::cursor::Cursor;
use crate::item_id::ItemId;
use crate::items::ClosestElem;
use crate::items::PlotConfig;
use crate::items::PlotGeometry;
Expand Down Expand Up @@ -161,13 +162,15 @@ impl BarChart {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// The id only has to be unique within the plot.
///
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
13 changes: 8 additions & 5 deletions egui_plot/src/items/box_plot.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::hash::Hash;
use std::ops::RangeInclusive;

use egui::Color32;
use egui::CornerRadius;
use egui::Id;
use egui::Shape;
use egui::Stroke;
use egui::Ui;
Expand All @@ -16,6 +16,7 @@ use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::colors::highlighted_color;
use crate::cursor::Cursor;
use crate::item_id::ItemId;
use crate::items::ClosestElem;
use crate::items::PlotConfig;
use crate::items::PlotGeometry;
Expand Down Expand Up @@ -127,13 +128,15 @@ impl BoxPlot {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// The id only has to be unique within the plot.
///
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
11 changes: 7 additions & 4 deletions egui_plot/src/items/filled_area.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::hash::Hash;
use std::ops::RangeInclusive;
use std::sync::Arc;

use egui::Color32;
use egui::Id;
use egui::Mesh;
use egui::Pos2;
use egui::Shape;
Expand All @@ -14,6 +14,7 @@ use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::colors::DEFAULT_FILL_ALPHA;
use crate::data::PlotPoints;
use crate::item_id::ItemId;
use crate::items::PlotGeometry;
use crate::items::PlotItem;
use crate::items::PlotItemBase;
Expand Down Expand Up @@ -115,10 +116,12 @@ impl FilledArea {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// The id only has to be unique within the plot.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
23 changes: 14 additions & 9 deletions egui_plot/src/items/line.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use core::hash::Hash;
use std::ops::RangeInclusive;

use egui::Color32;
use egui::Id;
use egui::Shape;
use egui::Stroke;
use egui::Ui;
Expand All @@ -13,6 +13,7 @@ use crate::aesthetics::LineStyle;
use crate::axis::PlotTransform;
use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::item_id::ItemId;
use crate::items::PlotGeometry;
use crate::items::PlotItem;
use crate::items::PlotItemBase;
Expand Down Expand Up @@ -97,13 +98,15 @@ impl HLine {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// The id only has to be unique within the plot.
///
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down Expand Up @@ -232,13 +235,15 @@ impl VLine {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// The id only has to be unique within the plot.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
12 changes: 7 additions & 5 deletions egui_plot/src/items/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::ops::RangeInclusive;

use egui::Align2;
use egui::Color32;
use egui::Id;
use egui::PopupAnchor;
use egui::Pos2;
use egui::Shape;
Expand All @@ -22,6 +21,7 @@ use crate::axis::PlotTransform;
use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::cursor::Cursor;
use crate::item_id::ItemId;
pub use crate::items::arrows::Arrows;
pub use crate::items::bar_chart::Bar;
pub use crate::items::bar_chart::BarChart;
Expand Down Expand Up @@ -61,15 +61,15 @@ mod text;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PlotItemBase {
name: String,
id: Id,
id: ItemId,
highlight: bool,
allow_hover: bool,
}

impl PlotItemBase {
/// Create a new plot item base with the given name.
pub fn new(name: String) -> Self {
let id = Id::new(&name);
let id = ItemId::new(&name);
Self {
name,
id,
Expand Down Expand Up @@ -141,8 +141,10 @@ pub trait PlotItem {
/// Returns a mutable reference to the base data of the plot item.
fn base_mut(&mut self) -> &mut PlotItemBase;

/// Returns the ID of the plot item.
fn id(&self) -> Id {
/// Returns the [`ItemId`] of the plot item.
///
/// This only identifies the item within its plot.
fn id(&self) -> ItemId {
self.base().id
}

Expand Down
13 changes: 8 additions & 5 deletions egui_plot/src/items/plot_image.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use core::hash::Hash;
use std::ops::RangeInclusive;

use egui::Color32;
use egui::CornerRadius;
use egui::Id;
use egui::ImageOptions;
use egui::Shape;
use egui::Stroke;
Expand All @@ -16,6 +16,7 @@ use emath::pos2;
use crate::axis::PlotTransform;
use crate::bounds::PlotBounds;
use crate::bounds::PlotPoint;
use crate::item_id::ItemId;
use crate::items::PlotGeometry;
use crate::items::PlotItem;
use crate::items::PlotItemBase;
Expand Down Expand Up @@ -114,13 +115,15 @@ impl PlotImage {
self
}

/// Sets the id of this plot item.
/// Sets the [`ItemId`] of this plot item.
///
/// By default the id is determined from the name passed to [`Self::new`],
/// The id only has to be unique within the plot.
///
/// By default the id is derived from the name passed to [`Self::new`],
/// but it can be explicitly set to a different value.
#[inline]
pub fn id(mut self, id: impl Into<Id>) -> Self {
self.base_mut().id = id.into();
pub fn id(mut self, id: impl Hash) -> Self {
self.base_mut().id = ItemId::new(id);
self
}
}
Expand Down
Loading
Loading