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();
}
}