rosu_map/section/hit_objects/slider/
path.rs

1use crate::{section::general::GameMode, util::Pos};
2
3use super::{
4    curve::{BorrowedCurve, Curve, CurveBuffers},
5    path_type::PathType,
6};
7
8/// The path of a [`HitObjectSlider`].
9///
10/// [`HitObjectSlider`]: crate::section::hit_objects::HitObjectSlider
11#[derive(Clone, Debug)]
12pub struct SliderPath {
13    mode: GameMode,
14    control_points: Vec<PathControlPoint>,
15    expected_dist: Option<f64>,
16    curve: Option<Curve>,
17}
18
19impl SliderPath {
20    /// Creates a new [`SliderPath`].
21    ///
22    /// The contained [`Curve`] will not necessarily be calculated yet, only
23    /// when accessing it with methods such as [`SliderPath::curve`].
24    pub const fn new(
25        mode: GameMode,
26        control_points: Vec<PathControlPoint>,
27        expected_dist: Option<f64>,
28    ) -> Self {
29        Self {
30            mode,
31            control_points,
32            expected_dist,
33            curve: None,
34        }
35    }
36
37    /// Returns an immutable reference to the control points.
38    pub fn control_points(&self) -> &[PathControlPoint] {
39        &self.control_points
40    }
41
42    /// Returns the expected distance.
43    pub const fn expected_dist(&self) -> Option<f64> {
44        self.expected_dist
45    }
46
47    /// Returns a reference to the [`Curve`].
48    ///
49    /// If the curve has not yet been accessed, it needs to be calculated
50    /// first.
51    ///
52    /// In case curves of multiple slider paths are being calculated, it is
53    /// recommended to initialize [`CurveBuffers`] and pass a mutable reference
54    /// of it to [`SliderPath::curve_with_bufs`] so the buffers are re-used for
55    /// all sliders.
56    ///
57    /// Alternatively, to avoid storing the curve altogether because it will be
58    /// accessed only once, using [`SliderPath::borrowed_curve`] should be
59    /// preferred.
60    pub fn curve(&mut self) -> &Curve {
61        if let Some(ref curve) = self.curve {
62            curve
63        } else {
64            let curve = self.calculate_curve();
65
66            self.curve.insert(curve)
67        }
68    }
69
70    /// Returns a reference to the [`Curve`].
71    ///
72    /// If the curve has not yet been accessed, it needs to be calculated
73    /// first.
74    ///
75    /// In case the curve will be accessed only once, using
76    /// [`SliderPath::borrowed_curve`] should be preferred.
77    pub fn curve_with_bufs(&mut self, bufs: &mut CurveBuffers) -> &Curve {
78        if let Some(ref curve) = self.curve {
79            curve
80        } else {
81            let curve = self.calculate_curve_with_bufs(bufs);
82
83            self.curve.insert(curve)
84        }
85    }
86
87    /// Returns a [`BorrowedCurve`].
88    ///
89    /// If the curve has been calculated before, the returned curve will borrow
90    /// from it. Otherwise, it will be calculated and returned **without**
91    /// storing it by borrowing from the given [`CurveBuffers`].
92    ///
93    /// This should be preferred over [`SliderPath::curve_with_bufs`] if the
94    /// curve will be accessed only once.
95    pub fn borrowed_curve<'a, 'b: 'a>(&'a self, bufs: &'b mut CurveBuffers) -> BorrowedCurve<'a> {
96        if let Some(ref curve) = self.curve {
97            curve.as_borrowed_curve()
98        } else {
99            BorrowedCurve::new(self.mode, &self.control_points, self.expected_dist, bufs)
100        }
101    }
102
103    /// Returns a mutable reference to the control points.
104    ///
105    /// Note that calling this method will invalidate the stored curve
106    /// so it must be recalculated on its next access.
107    pub fn control_points_mut(&mut self) -> &mut Vec<PathControlPoint> {
108        self.clear_curve();
109
110        &mut self.control_points
111    }
112
113    /// Returns a mutable reference to the expected distance.
114    ///
115    /// Note that calling this method will invalidate the stored curve
116    /// so it must be recalculated on its next access.
117    pub fn expected_dist_mut(&mut self) -> &mut Option<f64> {
118        self.clear_curve();
119
120        &mut self.expected_dist
121    }
122
123    /// Remove the stored curve so that it has to be re-calculated when
124    /// accessing it the next time.
125    pub fn clear_curve(&mut self) {
126        self.curve = None;
127    }
128
129    fn calculate_curve(&self) -> Curve {
130        self.calculate_curve_with_bufs(&mut CurveBuffers::default())
131    }
132
133    fn calculate_curve_with_bufs(&self, bufs: &mut CurveBuffers) -> Curve {
134        Curve::new(self.mode, &self.control_points, self.expected_dist, bufs)
135    }
136}
137
138impl PartialEq for SliderPath {
139    fn eq(&self, other: &Self) -> bool {
140        self.control_points == other.control_points
141    }
142}
143
144/// A positional control point of a curve.
145#[derive(Copy, Clone, Debug, Default, PartialEq)]
146pub struct PathControlPoint {
147    pub pos: Pos,
148    pub path_type: Option<PathType>,
149}
150
151impl PathControlPoint {
152    /// Initialize a new [`PathControlPoint`].
153    pub const fn new(pos: Pos) -> Self {
154        Self {
155            pos,
156            path_type: None,
157        }
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164
165    #[test]
166    fn borrowed_curve() {
167        let mut bufs = CurveBuffers::default();
168        let mut path = SliderPath::new(GameMode::Osu, Vec::new(), None);
169
170        // freshly calculate the curve; lifetime will depend on `bufs`
171        let borrowed_curve = path.borrowed_curve(&mut bufs);
172
173        // access to let the borrow checker know it will be used
174        let _ = borrowed_curve.dist();
175
176        // calculate **and store** the curve
177        let _ = path.curve_with_bufs(&mut bufs);
178
179        // access the stored curve; lifetime will depend on `path`
180        let borrowed_curve = path.borrowed_curve(&mut bufs);
181
182        // access to let the borrow checker know it will be used
183        let _ = borrowed_curve.dist();
184    }
185}