diff --git a/demo/src/plot_demo.rs b/demo/src/plot_demo.rs index a669648..f601acc 100644 --- a/demo/src/plot_demo.rs +++ b/demo/src/plot_demo.rs @@ -209,9 +209,9 @@ impl LineDemo { }); } - fn circle(&self) -> Line { + fn circle<'a>(&self) -> Line<'a> { let n = 512; - let circle_points: PlotPoints = (0..=n) + let circle_points: PlotPoints<'_> = (0..=n) .map(|i| { let t = remap(i as f64, 0.0..=(n as f64), 0.0..=TAU); let r = self.circle_radius; @@ -227,7 +227,7 @@ impl LineDemo { .name("circle") } - fn sin(&self) -> Line { + fn sin<'a>(&self) -> Line<'a> { let time = self.time; Line::new(PlotPoints::from_explicit_callback( move |x| 0.5 * (2.0 * x).sin() * time.sin(), @@ -239,7 +239,7 @@ impl LineDemo { .name("wave") } - fn thingy(&self) -> Line { + fn thingy<'a>(&self) -> Line<'a> { let time = self.time; Line::new(PlotPoints::from_parametric_callback( move |t| ((2.0 * t + time).sin(), (3.0 * t).sin()), @@ -304,7 +304,7 @@ impl Default for MarkerDemo { } impl MarkerDemo { - fn markers(&self) -> Vec { + fn markers<'a>(&self) -> Vec> { MarkerShape::all() .enumerate() .map(|(i, marker)| { @@ -367,7 +367,7 @@ struct LegendDemo { } impl LegendDemo { - fn line_with_slope(slope: f64) -> Line { + fn line_with_slope<'a>(slope: f64) -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| slope * x, .., @@ -375,7 +375,7 @@ impl LegendDemo { )) } - fn sin() -> Line { + fn sin<'a>() -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| x.sin(), .., @@ -383,7 +383,7 @@ impl LegendDemo { )) } - fn cos() -> Line { + fn cos<'a>() -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| x.cos(), .., @@ -444,7 +444,7 @@ impl CustomAxesDemo { const MINS_PER_DAY: f64 = 24.0 * 60.0; const MINS_PER_H: f64 = 60.0; - fn logistic_fn() -> Line { + fn logistic_fn<'a>() -> Line<'a> { fn days(min: f64) -> f64 { CustomAxesDemo::MINS_PER_DAY * min } @@ -598,7 +598,7 @@ impl Default for LinkedAxesDemo { } impl LinkedAxesDemo { - fn line_with_slope(slope: f64) -> Line { + fn line_with_slope<'a>(slope: f64) -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| slope * x, .., @@ -606,7 +606,7 @@ impl LinkedAxesDemo { )) } - fn sin() -> Line { + fn sin<'a>() -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| x.sin(), .., @@ -614,7 +614,7 @@ impl LinkedAxesDemo { )) } - fn cos() -> Line { + fn cos<'a>() -> Line<'a> { Line::new(PlotPoints::from_explicit_callback( move |x| x.cos(), .., @@ -622,7 +622,7 @@ impl LinkedAxesDemo { )) } - fn configure_plot(plot_ui: &mut egui_plot::PlotUi) { + fn configure_plot(plot_ui: &mut egui_plot::PlotUi<'_>) { plot_ui.line(Self::line_with_slope(0.5)); plot_ui.line(Self::line_with_slope(1.0)); plot_ui.line(Self::line_with_slope(2.0)); diff --git a/egui_plot/src/items/mod.rs b/egui_plot/src/items/mod.rs index 6d5f7cf..59d8915 100644 --- a/egui_plot/src/items/mod.rs +++ b/egui_plot/src/items/mod.rs @@ -420,8 +420,8 @@ impl PlotItem for VLine { } /// A series of values forming a path. -pub struct Line { - pub(super) series: PlotPoints, +pub struct Line<'a> { + pub(super) series: PlotPoints<'a>, pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, @@ -431,8 +431,8 @@ pub struct Line { id: Option, } -impl Line { - pub fn new(series: impl Into) -> Self { +impl<'a> Line<'a> { + pub fn new(series: impl Into>) -> Self { Self { series: series.into(), stroke: Stroke::new(1.5, Color32::TRANSPARENT), // Note: a stroke of 1.0 (or less) can look bad on low-dpi-screens @@ -522,7 +522,7 @@ fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option { .then_some(((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y)) } -impl PlotItem for Line { +impl<'a> PlotItem for Line<'a> { fn shapes(&self, _ui: &Ui, transform: &PlotTransform, shapes: &mut Vec) { let Self { series, @@ -620,8 +620,8 @@ impl PlotItem for Line { } /// A convex polygon. -pub struct Polygon { - pub(super) series: PlotPoints, +pub struct Polygon<'a> { + pub(super) series: PlotPoints<'a>, pub(super) stroke: Stroke, pub(super) name: String, pub(super) highlight: bool, @@ -631,8 +631,8 @@ pub struct Polygon { id: Option, } -impl Polygon { - pub fn new(series: impl Into) -> Self { +impl<'a> Polygon<'a> { + pub fn new(series: impl Into>) -> Self { Self { series: series.into(), stroke: Stroke::new(1.0, Color32::TRANSPARENT), @@ -709,7 +709,7 @@ impl Polygon { } } -impl PlotItem for Polygon { +impl<'a> PlotItem for Polygon<'a> { fn shapes(&self, _ui: &Ui, transform: &PlotTransform, shapes: &mut Vec) { let Self { series, @@ -918,8 +918,8 @@ impl PlotItem for Text { } /// A set of points. -pub struct Points { - pub(super) series: PlotPoints, +pub struct Points<'a> { + pub(super) series: PlotPoints<'a>, pub(super) shape: MarkerShape, @@ -942,8 +942,8 @@ pub struct Points { id: Option, } -impl Points { - pub fn new(series: impl Into) -> Self { +impl<'a> Points<'a> { + pub fn new(series: impl Into>) -> Self { Self { series: series.into(), shape: MarkerShape::Circle, @@ -1028,7 +1028,7 @@ impl Points { } } -impl PlotItem for Points { +impl<'a> PlotItem for Points<'a> { #[allow(clippy::too_many_lines)] // TODO(emilk): shorten this function fn shapes(&self, _ui: &Ui, transform: &PlotTransform, shapes: &mut Vec) { let sqrt_3 = 3_f32.sqrt(); @@ -1196,9 +1196,9 @@ impl PlotItem for Points { } /// A set of arrows. -pub struct Arrows { - pub(super) origins: PlotPoints, - pub(super) tips: PlotPoints, +pub struct Arrows<'a> { + pub(super) origins: PlotPoints<'a>, + pub(super) tips: PlotPoints<'a>, pub(super) tip_length: Option, pub(super) color: Color32, pub(super) name: String, @@ -1207,8 +1207,8 @@ pub struct Arrows { id: Option, } -impl Arrows { - pub fn new(origins: impl Into, tips: impl Into) -> Self { +impl<'a> Arrows<'a> { + pub fn new(origins: impl Into>, tips: impl Into>) -> Self { Self { origins: origins.into(), tips: tips.into(), @@ -1270,7 +1270,7 @@ impl Arrows { } } -impl PlotItem for Arrows { +impl<'a> PlotItem for Arrows<'a> { fn shapes(&self, _ui: &Ui, transform: &PlotTransform, shapes: &mut Vec) { let Self { origins, diff --git a/egui_plot/src/items/values.rs b/egui_plot/src/items/values.rs index 1251396..fe2be68 100644 --- a/egui_plot/src/items/values.rs +++ b/egui_plot/src/items/values.rs @@ -154,37 +154,45 @@ impl Default for Orientation { /// Represents many [`PlotPoint`]s. /// /// These can be an owned `Vec` or generated with a function. -pub enum PlotPoints { +pub enum PlotPoints<'a> { Owned(Vec), - Generator(ExplicitGenerator), - // Borrowed(&[PlotPoint]), // TODO(EmbersArc): Lifetimes are tricky in this case. + Generator(ExplicitGenerator<'a>), + Borrowed(&'a [PlotPoint]), } -impl Default for PlotPoints { +impl<'a> Default for PlotPoints<'a> { fn default() -> Self { Self::Owned(Vec::new()) } } -impl From<[f64; 2]> for PlotPoints { +impl<'a> From<[f64; 2]> for PlotPoints<'a> { fn from(coordinate: [f64; 2]) -> Self { Self::new(vec![coordinate]) } } -impl From> for PlotPoints { +impl<'a> From> for PlotPoints<'a> { + #[inline] fn from(coordinates: Vec<[f64; 2]>) -> Self { Self::new(coordinates) } } -impl FromIterator<[f64; 2]> for PlotPoints { +impl<'a> From<&'a [PlotPoint]> for PlotPoints<'a> { + #[inline] + fn from(points: &'a [PlotPoint]) -> Self { + Self::Borrowed(points) + } +} + +impl<'a> FromIterator<[f64; 2]> for PlotPoints<'a> { fn from_iter>(iter: T) -> Self { Self::Owned(iter.into_iter().map(|point| point.into()).collect()) } } -impl PlotPoints { +impl<'a> PlotPoints<'a> { pub fn new(points: Vec<[f64; 2]>) -> Self { Self::from_iter(points) } @@ -193,12 +201,13 @@ impl PlotPoints { match self { Self::Owned(points) => points.as_slice(), Self::Generator(_) => &[], + Self::Borrowed(points) => points, } } /// Draw a line based on a function `y=f(x)`, a range (which can be infinite) for x and the number of points. pub fn from_explicit_callback( - function: impl Fn(f64) -> f64 + 'static, + function: impl Fn(f64) -> f64 + 'a, x_range: impl RangeBounds, points: usize, ) -> Self { @@ -271,6 +280,7 @@ impl PlotPoints { match self { Self::Owned(points) => points.is_empty(), Self::Generator(_) => false, + Self::Borrowed(points) => points.is_empty(), } } @@ -314,6 +324,13 @@ impl PlotPoints { bounds } Self::Generator(generator) => generator.estimate_bounds(), + Self::Borrowed(points) => { + let mut bounds = PlotBounds::NOTHING; + for point in *points { + bounds.extend_with(point); + } + bounds + } } } } @@ -374,13 +391,13 @@ pub enum PlotGeometry<'a> { // ---------------------------------------------------------------------------- /// Describes a function y = f(x) with an optional range for x and a number of points. -pub struct ExplicitGenerator { - function: Box f64>, +pub struct ExplicitGenerator<'a> { + function: Box f64 + 'a>, x_range: RangeInclusive, points: usize, } -impl ExplicitGenerator { +impl ExplicitGenerator<'_> { fn estimate_bounds(&self) -> PlotBounds { let mut bounds = PlotBounds::NOTHING; diff --git a/egui_plot/src/legend.rs b/egui_plot/src/legend.rs index 8e81752..b72b737 100644 --- a/egui_plot/src/legend.rs +++ b/egui_plot/src/legend.rs @@ -187,10 +187,10 @@ pub(super) struct LegendWidget { impl LegendWidget { /// Create a new legend from items, the names of items that are hidden and the style of the /// text. Returns `None` if the legend has no entries. - pub(super) fn try_new( + pub(super) fn try_new<'a>( rect: Rect, config: Legend, - items: &[Box], + items: &[Box], hidden_items: &ahash::HashSet, // Existing hidden items in the plot memory. ) -> Option { // If `config.hidden_items` is not `None`, it is used. diff --git a/egui_plot/src/lib.rs b/egui_plot/src/lib.rs index 50b12cf..52aa108 100644 --- a/egui_plot/src/lib.rs +++ b/egui_plot/src/lib.rs @@ -728,20 +728,20 @@ impl<'a> Plot<'a> { } /// Interact with and add items to the plot and finally draw it. - pub fn show( + pub fn show<'b, R>( self, ui: &mut Ui, - build_fn: impl FnOnce(&mut PlotUi) -> R + 'a, + build_fn: impl FnOnce(&mut PlotUi<'b>) -> R + 'a, ) -> PlotResponse { self.show_dyn(ui, Box::new(build_fn)) } #[allow(clippy::too_many_lines)] // TODO(emilk): shorten this function #[allow(clippy::type_complexity)] // build_fn - fn show_dyn( + fn show_dyn<'b, R>( self, ui: &mut Ui, - build_fn: Box R + 'a>, + build_fn: Box) -> R + 'a>, ) -> PlotResponse { let Self { id_source, @@ -1467,7 +1467,7 @@ pub fn uniform_grid_spacer<'a>(spacer: impl Fn(GridInput) -> [f64; 3] + 'a) -> G // ---------------------------------------------------------------------------- struct PreparedPlot<'a> { - items: Vec>, + items: Vec>, show_x: bool, show_y: bool, label_formatter: LabelFormatter<'a>, diff --git a/egui_plot/src/plot_ui.rs b/egui_plot/src/plot_ui.rs index 8b24650..973c2b1 100644 --- a/egui_plot/src/plot_ui.rs +++ b/egui_plot/src/plot_ui.rs @@ -7,9 +7,9 @@ use crate::Plot; /// Provides methods to interact with a plot while building it. It is the single argument of the closure /// provided to [`Plot::show`]. See [`Plot`] for an example of how to use it. -pub struct PlotUi { +pub struct PlotUi<'a> { pub(crate) ctx: egui::Context, - pub(crate) items: Vec>, + pub(crate) items: Vec>, pub(crate) next_auto_color_idx: usize, pub(crate) last_plot_transform: PlotTransform, pub(crate) last_auto_bounds: Vec2b, @@ -17,7 +17,7 @@ pub struct PlotUi { pub(crate) bounds_modifications: Vec, } -impl PlotUi { +impl<'a> PlotUi<'a> { fn auto_color(&mut self) -> Color32 { let i = self.next_auto_color_idx; self.next_auto_color_idx += 1; @@ -122,12 +122,12 @@ impl PlotUi { } /// Add an arbitrary item. - pub fn add(&mut self, item: impl PlotItem + 'static) { + pub fn add(&mut self, item: impl PlotItem + 'a) { self.items.push(Box::new(item)); } /// Add a data line. - pub fn line(&mut self, mut line: crate::Line) { + pub fn line(&mut self, mut line: crate::Line<'a>) { if line.series.is_empty() { return; }; @@ -140,7 +140,7 @@ impl PlotUi { } /// Add a polygon. The polygon has to be convex. - pub fn polygon(&mut self, mut polygon: crate::Polygon) { + pub fn polygon(&mut self, mut polygon: crate::Polygon<'a>) { if polygon.series.is_empty() { return; }; @@ -162,7 +162,7 @@ impl PlotUi { } /// Add data points. - pub fn points(&mut self, mut points: crate::Points) { + pub fn points(&mut self, mut points: crate::Points<'a>) { if points.series.is_empty() { return; }; @@ -175,7 +175,7 @@ impl PlotUi { } /// Add arrows. - pub fn arrows(&mut self, mut arrows: crate::Arrows) { + pub fn arrows(&mut self, mut arrows: crate::Arrows<'a>) { if arrows.origins.is_empty() || arrows.tips.is_empty() { return; };