Skip to content

Commit 1282784

Browse files
Fabus1184hacknus
authored andcommitted
Introduce lifetime to egui_plot::Plot to replace 'static fields (emilk#4435)
* Closes emilk#4434 Shouldn't break anything, because when all arguments have a 'static lifetime (required without this PR), the Plot is also 'static and can be used like before.
1 parent 682fc92 commit 1282784

File tree

3 files changed

+56
-52
lines changed

3 files changed

+56
-52
lines changed

crates/egui_plot/src/axis.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use egui::{
88

99
use super::{transform::PlotTransform, GridMark};
1010

11-
pub(super) type AxisFormatterFn = dyn Fn(GridMark, usize, &RangeInclusive<f64>) -> String;
11+
pub(super) type AxisFormatterFn<'a> = dyn Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a;
1212

1313
/// X or Y axis.
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -98,9 +98,9 @@ impl From<Placement> for VPlacement {
9898
///
9999
/// Used to configure axis label and ticks.
100100
#[derive(Clone)]
101-
pub struct AxisHints {
101+
pub struct AxisHints<'a> {
102102
pub(super) label: WidgetText,
103-
pub(super) formatter: Arc<AxisFormatterFn>,
103+
pub(super) formatter: Arc<AxisFormatterFn<'a>>,
104104
pub(super) digits: usize,
105105
pub(super) placement: Placement,
106106
pub(super) label_spacing: Rangef,
@@ -109,7 +109,7 @@ pub struct AxisHints {
109109
// TODO(JohannesProgrammiert): this just a guess. It might cease to work if a user changes font size.
110110
const LINE_HEIGHT: f32 = 12.0;
111111

112-
impl AxisHints {
112+
impl<'a> AxisHints<'a> {
113113
/// Initializes a default axis configuration for the X axis.
114114
pub fn new_x() -> Self {
115115
Self::new(Axis::X)
@@ -145,7 +145,7 @@ impl AxisHints {
145145
/// The second parameter of `formatter` is the currently shown range on this axis.
146146
pub fn formatter(
147147
mut self,
148-
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
148+
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
149149
) -> Self {
150150
self.formatter = Arc::new(fmt);
151151
self
@@ -230,19 +230,19 @@ impl AxisHints {
230230
}
231231

232232
#[derive(Clone)]
233-
pub(super) struct AxisWidget {
233+
pub(super) struct AxisWidget<'a> {
234234
pub range: RangeInclusive<f64>,
235-
pub hints: AxisHints,
235+
pub hints: AxisHints<'a>,
236236

237237
/// The region where we draw the axis labels.
238238
pub rect: Rect,
239239
pub transform: Option<PlotTransform>,
240240
pub steps: Arc<Vec<GridMark>>,
241241
}
242242

243-
impl AxisWidget {
243+
impl<'a> AxisWidget<'a> {
244244
/// if `rect` as width or height == 0, is will be automatically calculated from ticks and text.
245-
pub fn new(hints: AxisHints, rect: Rect) -> Self {
245+
pub fn new(hints: AxisHints<'a>, rect: Rect) -> Self {
246246
Self {
247247
range: (0.0..=0.0),
248248
hints,

crates/egui_plot/src/items/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub trait PlotItem {
8181
shapes: &mut Vec<Shape>,
8282
cursors: &mut Vec<Cursor>,
8383
plot: &PlotConfig<'_>,
84-
label_formatter: &LabelFormatter,
84+
label_formatter: &LabelFormatter<'_>,
8585
) {
8686
let points = match self.geometry() {
8787
PlotGeometry::Points(points) => points,
@@ -1735,7 +1735,7 @@ impl PlotItem for BarChart {
17351735
shapes: &mut Vec<Shape>,
17361736
cursors: &mut Vec<Cursor>,
17371737
plot: &PlotConfig<'_>,
1738-
_: &LabelFormatter,
1738+
_: &LabelFormatter<'_>,
17391739
) {
17401740
let bar = &self.bars[elem.index];
17411741

@@ -1909,7 +1909,7 @@ impl PlotItem for BoxPlot {
19091909
shapes: &mut Vec<Shape>,
19101910
cursors: &mut Vec<Cursor>,
19111911
plot: &PlotConfig<'_>,
1912-
_: &LabelFormatter,
1912+
_: &LabelFormatter<'_>,
19131913
) {
19141914
let box_plot = &self.boxes[elem.index];
19151915

@@ -2033,7 +2033,7 @@ pub(super) fn rulers_at_value(
20332033
plot: &PlotConfig<'_>,
20342034
shapes: &mut Vec<Shape>,
20352035
cursors: &mut Vec<Cursor>,
2036-
label_formatter: &LabelFormatter,
2036+
label_formatter: &LabelFormatter<'_>,
20372037
) {
20382038
if plot.show_x {
20392039
cursors.push(Cursor::Vertical { x: value.x });

crates/egui_plot/src/lib.rs

+43-39
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,22 @@ use axis::AxisWidget;
3737
use items::{horizontal_line, rulers_color, vertical_line};
3838
use legend::LegendWidget;
3939

40-
type LabelFormatterFn = dyn Fn(&str, &PlotPoint) -> String;
41-
pub type LabelFormatter = Option<Box<LabelFormatterFn>>;
40+
type LabelFormatterFn<'a> = dyn Fn(&str, &PlotPoint) -> String + 'a;
41+
pub type LabelFormatter<'a> = Option<Box<LabelFormatterFn<'a>>>;
4242

43-
type GridSpacerFn = dyn Fn(GridInput) -> Vec<GridMark>;
44-
type GridSpacer = Box<GridSpacerFn>;
43+
type GridSpacerFn<'a> = dyn Fn(GridInput) -> Vec<GridMark> + 'a;
44+
type GridSpacer<'a> = Box<GridSpacerFn<'a>>;
4545

46-
type CoordinatesFormatterFn = dyn Fn(&PlotPoint, &PlotBounds) -> String;
46+
type CoordinatesFormatterFn<'a> = dyn Fn(&PlotPoint, &PlotBounds) -> String + 'a;
4747

4848
/// Specifies the coordinates formatting when passed to [`Plot::coordinates_formatter`].
49-
pub struct CoordinatesFormatter {
50-
function: Box<CoordinatesFormatterFn>,
49+
pub struct CoordinatesFormatter<'a> {
50+
function: Box<CoordinatesFormatterFn<'a>>,
5151
}
5252

53-
impl CoordinatesFormatter {
53+
impl<'a> CoordinatesFormatter<'a> {
5454
/// Create a new formatter based on the pointer coordinate and the plot bounds.
55-
pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'static) -> Self {
55+
pub fn new(function: impl Fn(&PlotPoint, &PlotBounds) -> String + 'a) -> Self {
5656
Self {
5757
function: Box::new(function),
5858
}
@@ -72,7 +72,7 @@ impl CoordinatesFormatter {
7272
}
7373
}
7474

75-
impl Default for CoordinatesFormatter {
75+
impl Default for CoordinatesFormatter<'_> {
7676
fn default() -> Self {
7777
Self::with_decimals(3)
7878
}
@@ -143,7 +143,7 @@ pub struct PlotResponse<R> {
143143
/// Plot::new("my_plot").view_aspect(2.0).show(ui, |plot_ui| plot_ui.line(line));
144144
/// # });
145145
/// ```
146-
pub struct Plot {
146+
pub struct Plot<'a> {
147147
id_source: Id,
148148
id: Option<Id>,
149149

@@ -170,24 +170,24 @@ pub struct Plot {
170170

171171
show_x: bool,
172172
show_y: bool,
173-
label_formatter: LabelFormatter,
174-
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
175-
x_axes: Vec<AxisHints>, // default x axes
176-
y_axes: Vec<AxisHints>, // default y axes
173+
label_formatter: LabelFormatter<'a>,
174+
coordinates_formatter: Option<(Corner, CoordinatesFormatter<'a>)>,
175+
x_axes: Vec<AxisHints<'a>>, // default x axes
176+
y_axes: Vec<AxisHints<'a>>, // default y axes
177177
legend_config: Option<Legend>,
178178
show_background: bool,
179179
show_axes: Vec2b,
180180

181181
show_grid: Vec2b,
182182
grid_spacing: Rangef,
183-
grid_spacers: [GridSpacer; 2],
183+
grid_spacers: [GridSpacer<'a>; 2],
184184
sharp_grid_lines: bool,
185185
clamp_grid: bool,
186186

187187
sense: Sense,
188188
}
189189

190-
impl Plot {
190+
impl<'a> Plot<'a> {
191191
/// Give a unique id for each plot within the same [`Ui`].
192192
pub fn new(id_source: impl std::hash::Hash) -> Self {
193193
Self {
@@ -405,7 +405,7 @@ impl Plot {
405405
/// ```
406406
pub fn label_formatter(
407407
mut self,
408-
label_formatter: impl Fn(&str, &PlotPoint) -> String + 'static,
408+
label_formatter: impl Fn(&str, &PlotPoint) -> String + 'a,
409409
) -> Self {
410410
self.label_formatter = Some(Box::new(label_formatter));
411411
self
@@ -415,7 +415,7 @@ impl Plot {
415415
pub fn coordinates_formatter(
416416
mut self,
417417
position: Corner,
418-
formatter: CoordinatesFormatter,
418+
formatter: CoordinatesFormatter<'a>,
419419
) -> Self {
420420
self.coordinates_formatter = Some((position, formatter));
421421
self
@@ -452,7 +452,7 @@ impl Plot {
452452
///
453453
/// There are helpers for common cases, see [`log_grid_spacer`] and [`uniform_grid_spacer`].
454454
#[inline]
455-
pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'static) -> Self {
455+
pub fn x_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'a) -> Self {
456456
self.grid_spacers[0] = Box::new(spacer);
457457
self
458458
}
@@ -461,7 +461,7 @@ impl Plot {
461461
///
462462
/// See [`Self::x_grid_spacer`] for explanation.
463463
#[inline]
464-
pub fn y_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'static) -> Self {
464+
pub fn y_grid_spacer(mut self, spacer: impl Fn(GridInput) -> Vec<GridMark> + 'a) -> Self {
465465
self.grid_spacers[1] = Box::new(spacer);
466466
self
467467
}
@@ -662,7 +662,7 @@ impl Plot {
662662
/// * currently shown range on this axis.
663663
pub fn x_axis_formatter(
664664
mut self,
665-
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
665+
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
666666
) -> Self {
667667
if let Some(main) = self.x_axes.first_mut() {
668668
main.formatter = Arc::new(fmt);
@@ -678,7 +678,7 @@ impl Plot {
678678
/// * currently shown range on this axis.
679679
pub fn y_axis_formatter(
680680
mut self,
681-
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'static,
681+
fmt: impl Fn(GridMark, usize, &RangeInclusive<f64>) -> String + 'a,
682682
) -> Self {
683683
if let Some(main) = self.y_axes.first_mut() {
684684
main.formatter = Arc::new(fmt);
@@ -703,7 +703,7 @@ impl Plot {
703703
///
704704
/// More than one axis may be specified. The first specified axis is considered the main axis.
705705
#[inline]
706-
pub fn custom_x_axes(mut self, hints: Vec<AxisHints>) -> Self {
706+
pub fn custom_x_axes(mut self, hints: Vec<AxisHints<'a>>) -> Self {
707707
self.x_axes = hints;
708708
self
709709
}
@@ -712,17 +712,21 @@ impl Plot {
712712
///
713713
/// More than one axis may be specified. The first specified axis is considered the main axis.
714714
#[inline]
715-
pub fn custom_y_axes(mut self, hints: Vec<AxisHints>) -> Self {
715+
pub fn custom_y_axes(mut self, hints: Vec<AxisHints<'a>>) -> Self {
716716
self.y_axes = hints;
717717
self
718718
}
719719

720720
/// Interact with and add items to the plot and finally draw it.
721-
pub fn show<R>(self, ui: &mut Ui, build_fn: impl FnOnce(&mut PlotUi) -> R) -> PlotResponse<R> {
721+
pub fn show<R>(
722+
self,
723+
ui: &mut Ui,
724+
build_fn: impl FnOnce(&mut PlotUi) -> R + 'a,
725+
) -> PlotResponse<R> {
722726
self.show_dyn(ui, Box::new(build_fn))
723727
}
724728

725-
fn show_dyn<'a, R>(
729+
fn show_dyn<R>(
726730
self,
727731
ui: &mut Ui,
728732
build_fn: Box<dyn FnOnce(&mut PlotUi) -> R + 'a>,
@@ -1246,12 +1250,12 @@ impl Plot {
12461250
}
12471251

12481252
/// Returns the rect left after adding axes.
1249-
fn axis_widgets(
1253+
fn axis_widgets<'a>(
12501254
mem: Option<&PlotMemory>,
12511255
show_axes: Vec2b,
12521256
complete_rect: Rect,
1253-
[x_axes, y_axes]: [&[AxisHints]; 2],
1254-
) -> ([Vec<AxisWidget>; 2], Rect) {
1257+
[x_axes, y_axes]: [&'a [AxisHints<'a>]; 2],
1258+
) -> ([Vec<AxisWidget<'a>>; 2], Rect) {
12551259
// Next we want to create this layout.
12561260
// Indices are only examples.
12571261
//
@@ -1275,8 +1279,8 @@ fn axis_widgets(
12751279
// + +--------------------+---+
12761280
//
12771281

1278-
let mut x_axis_widgets = Vec::<AxisWidget>::new();
1279-
let mut y_axis_widgets = Vec::<AxisWidget>::new();
1282+
let mut x_axis_widgets = Vec::<AxisWidget<'_>>::new();
1283+
let mut y_axis_widgets = Vec::<AxisWidget<'_>>::new();
12801284

12811285
// Will shrink as we add more axes.
12821286
let mut rect_left = complete_rect;
@@ -1404,7 +1408,7 @@ pub struct GridMark {
14041408
///
14051409
/// The logarithmic base, expressing how many times each grid unit is subdivided.
14061410
/// 10 is a typical value, others are possible though.
1407-
pub fn log_grid_spacer(log_base: i64) -> GridSpacer {
1411+
pub fn log_grid_spacer(log_base: i64) -> GridSpacer<'static> {
14081412
let log_base = log_base as f64;
14091413
let step_sizes = move |input: GridInput| -> Vec<GridMark> {
14101414
// handle degenerate cases
@@ -1435,7 +1439,7 @@ pub fn log_grid_spacer(log_base: i64) -> GridSpacer {
14351439
///
14361440
/// Why only 3 step sizes? Three is the number of different line thicknesses that egui typically uses in the grid.
14371441
/// Ideally, those 3 are not hardcoded values, but depend on the visible range (accessible through `GridInput`).
1438-
pub fn uniform_grid_spacer(spacer: impl Fn(GridInput) -> [f64; 3] + 'static) -> GridSpacer {
1442+
pub fn uniform_grid_spacer<'a>(spacer: impl Fn(GridInput) -> [f64; 3] + 'a) -> GridSpacer<'a> {
14391443
let get_marks = move |input: GridInput| -> Vec<GridMark> {
14401444
let bounds = input.bounds;
14411445
let step_sizes = spacer(input);
@@ -1447,17 +1451,17 @@ pub fn uniform_grid_spacer(spacer: impl Fn(GridInput) -> [f64; 3] + 'static) ->
14471451

14481452
// ----------------------------------------------------------------------------
14491453

1450-
struct PreparedPlot {
1454+
struct PreparedPlot<'a> {
14511455
items: Vec<Box<dyn PlotItem>>,
14521456
show_x: bool,
14531457
show_y: bool,
1454-
label_formatter: LabelFormatter,
1455-
coordinates_formatter: Option<(Corner, CoordinatesFormatter)>,
1458+
label_formatter: LabelFormatter<'a>,
1459+
coordinates_formatter: Option<(Corner, CoordinatesFormatter<'a>)>,
14561460
// axis_formatters: [AxisFormatter; 2],
14571461
transform: PlotTransform,
14581462
show_grid: Vec2b,
14591463
grid_spacing: Rangef,
1460-
grid_spacers: [GridSpacer; 2],
1464+
grid_spacers: [GridSpacer<'a>; 2],
14611465
draw_cursor_x: bool,
14621466
draw_cursor_y: bool,
14631467
draw_cursors: Vec<Cursor>,
@@ -1466,7 +1470,7 @@ struct PreparedPlot {
14661470
clamp_grid: bool,
14671471
}
14681472

1469-
impl PreparedPlot {
1473+
impl<'a> PreparedPlot<'a> {
14701474
fn ui(self, ui: &mut Ui, response: &Response) -> (Vec<Cursor>, Option<Id>) {
14711475
let mut axes_shapes = Vec::new();
14721476

0 commit comments

Comments
 (0)