1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use crate::util::Pos;

use super::{
    curve::{BorrowedCurve, Curve, CurveBuffers},
    path_type::PathType,
};

/// The path of a [`HitObjectSlider`].
///
/// [`HitObjectSlider`]: crate::section::hit_objects::HitObjectSlider
#[derive(Clone, Debug)]
pub struct SliderPath {
    control_points: Vec<PathControlPoint>,
    expected_dist: Option<f64>,
    curve: Option<Curve>,
}

impl SliderPath {
    /// Creates a new [`SliderPath`].
    ///
    /// The contained [`Curve`] will not necessarily be calculated yet, only
    /// when accessing it with methods such as [`SliderPath::curve`].
    pub const fn new(control_points: Vec<PathControlPoint>, expected_dist: Option<f64>) -> Self {
        Self {
            control_points,
            expected_dist,
            curve: None,
        }
    }

    /// Returns an immutable reference to the control points.
    pub fn control_points(&self) -> &[PathControlPoint] {
        &self.control_points
    }

    /// Returns the expected distance.
    pub const fn expected_dist(&self) -> Option<f64> {
        self.expected_dist
    }

    /// Returns a reference to the [`Curve`].
    ///
    /// If the curve has not yet been accessed, it needs to be calculated
    /// first.
    ///
    /// In case curves of multiple slider paths are being calculated, it is
    /// recommended to initialize [`CurveBuffers`] and pass a mutable reference
    /// of it to [`SliderPath::curve_with_bufs`] so the buffers are re-used for
    /// all sliders.
    ///
    /// Alternatively, to avoid storing the curve altogether because it will be
    /// accessed only once, using [`SliderPath::borrowed_curve`] should be
    /// preferred.
    pub fn curve(&mut self) -> &Curve {
        if let Some(ref curve) = self.curve {
            curve
        } else {
            let curve = self.calculate_curve();

            self.curve.insert(curve)
        }
    }

    /// Returns a reference to the [`Curve`].
    ///
    /// If the curve has not yet been accessed, it needs to be calculated
    /// first.
    ///
    /// In case the curve will be accessed only once, using
    /// [`SliderPath::borrowed_curve`] should be preferred.
    pub fn curve_with_bufs(&mut self, bufs: &mut CurveBuffers) -> &Curve {
        if let Some(ref curve) = self.curve {
            curve
        } else {
            let curve = self.calculate_curve_with_bufs(bufs);

            self.curve.insert(curve)
        }
    }

    /// Returns a [`BorrowedCurve`].
    ///
    /// If the curve has been calculated before, the returned curve will borrow
    /// from it. Otherwise, it will be calculated and returned **without**
    /// storing it by borrowing from the given [`CurveBuffers`].
    ///
    /// This should be preferred over [`SliderPath::curve_with_bufs`] if the
    /// curve will be accessed only once.
    pub fn borrowed_curve<'a, 'b: 'a>(&'a self, bufs: &'b mut CurveBuffers) -> BorrowedCurve<'_> {
        if let Some(ref curve) = self.curve {
            curve.as_borrowed_curve()
        } else {
            BorrowedCurve::new(&self.control_points, self.expected_dist, bufs)
        }
    }

    /// Returns a mutable reference to the control points.
    ///
    /// Note that calling this method will invalidate the stored curve
    /// so it must be recalculated on its next access.
    pub fn control_points_mut(&mut self) -> &mut Vec<PathControlPoint> {
        self.clear_curve();

        &mut self.control_points
    }

    /// Returns a mutable reference to the expected distance.
    ///
    /// Note that calling this method will invalidate the stored curve
    /// so it must be recalculated on its next access.
    pub fn expected_dist_mut(&mut self) -> &mut Option<f64> {
        self.clear_curve();

        &mut self.expected_dist
    }

    /// Remove the stored curve so that it has to be re-calculated when
    /// accessing it the next time.
    pub fn clear_curve(&mut self) {
        self.curve = None;
    }

    fn calculate_curve(&self) -> Curve {
        self.calculate_curve_with_bufs(&mut CurveBuffers::default())
    }

    fn calculate_curve_with_bufs(&self, bufs: &mut CurveBuffers) -> Curve {
        Curve::new(&self.control_points, self.expected_dist, bufs)
    }
}

impl PartialEq for SliderPath {
    fn eq(&self, other: &Self) -> bool {
        self.control_points == other.control_points
    }
}

/// A positional control point of a curve.
#[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct PathControlPoint {
    pub pos: Pos,
    pub path_type: Option<PathType>,
}

impl PathControlPoint {
    /// Initialize a new [`PathControlPoint`].
    pub const fn new(pos: Pos) -> Self {
        Self {
            pos,
            path_type: None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn borrowed_curve() {
        let mut bufs = CurveBuffers::default();
        let mut path = SliderPath::new(Vec::new(), None);

        // freshly calculate the curve; lifetime will depend on `bufs`
        let borrowed_curve = path.borrowed_curve(&mut bufs);

        // access to let the borrow checker know it will be used
        let _ = borrowed_curve.dist();

        // calculate **and store** the curve
        let _ = path.curve_with_bufs(&mut bufs);

        // access the stored curve; lifetime will depend on `path`
        let borrowed_curve = path.borrowed_curve(&mut bufs);

        // access to let the borrow checker know it will be used
        let _ = borrowed_curve.dist();
    }
}