Use IntoIterator instead of Into<Vec<..>> in cubic splines interfaces (#16402)

# Objective

This was always a bit weird; `IntoIterator` is considered more idiomatic
in Rust.

The reason these used `Into<Vec<..>>` in the first place was (to my
knowledge) because of concerns that passing an already-owned vector
would cause a redundant allocation if the iterator API was used instead.
However, I have looked at simple examples for this scenario and the
generated assembly is identical (i.e. `into_iter().collect()` is
effectively converted to a no-op).

## Solution

As described in the title.

## Testing

It compiles. Ran existing tests.

## Migration Guide

The cubic splines API now uses `IntoIterator` in places where it used
`Into<Vec<..>>`. For most users, this will have little to no effect (it
is largely more permissive). However, in case you were using some
unusual input type that implements `Into<Vec<..>>` without implementing
`IntoIterator`, you can migrate by converting the input to a `Vec<..>`
before passing it into the interface.
This commit is contained in:
Matty Weatherley 2024-12-03 11:35:14 -08:00 committed by GitHub
parent 93dc596d2e
commit 9d142a8025
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -63,9 +63,9 @@ pub struct CubicBezier<P: VectorSpace> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl<P: VectorSpace> CubicBezier<P> { impl<P: VectorSpace> CubicBezier<P> {
/// Create a new cubic Bezier curve from sets of control points. /// Create a new cubic Bezier curve from sets of control points.
pub fn new(control_points: impl Into<Vec<[P; 4]>>) -> Self { pub fn new(control_points: impl IntoIterator<Item = [P; 4]>) -> Self {
Self { Self {
control_points: control_points.into(), control_points: control_points.into_iter().collect(),
} }
} }
} }
@ -287,18 +287,18 @@ pub struct CubicCardinalSpline<P: VectorSpace> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl<P: VectorSpace> CubicCardinalSpline<P> { impl<P: VectorSpace> CubicCardinalSpline<P> {
/// Build a new Cardinal spline. /// Build a new Cardinal spline.
pub fn new(tension: f32, control_points: impl Into<Vec<P>>) -> Self { pub fn new(tension: f32, control_points: impl IntoIterator<Item = P>) -> Self {
Self { Self {
tension, tension,
control_points: control_points.into(), control_points: control_points.into_iter().collect(),
} }
} }
/// Build a new Catmull-Rom spline, the special case of a Cardinal spline where tension = 1/2. /// Build a new Catmull-Rom spline, the special case of a Cardinal spline where tension = 1/2.
pub fn new_catmull_rom(control_points: impl Into<Vec<P>>) -> Self { pub fn new_catmull_rom(control_points: impl IntoIterator<Item = P>) -> Self {
Self { Self {
tension: 0.5, tension: 0.5,
control_points: control_points.into(), control_points: control_points.into_iter().collect(),
} }
} }
@ -444,9 +444,9 @@ pub struct CubicBSpline<P: VectorSpace> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl<P: VectorSpace> CubicBSpline<P> { impl<P: VectorSpace> CubicBSpline<P> {
/// Build a new B-Spline. /// Build a new B-Spline.
pub fn new(control_points: impl Into<Vec<P>>) -> Self { pub fn new(control_points: impl IntoIterator<Item = P>) -> Self {
Self { Self {
control_points: control_points.into(), control_points: control_points.into_iter().collect(),
} }
} }
@ -630,11 +630,11 @@ impl<P: VectorSpace> CubicNurbs<P> {
/// ///
/// At least 4 points must be provided, otherwise an error will be returned. /// At least 4 points must be provided, otherwise an error will be returned.
pub fn new( pub fn new(
control_points: impl Into<Vec<P>>, control_points: impl IntoIterator<Item = P>,
weights: Option<impl Into<Vec<f32>>>, weights: Option<impl IntoIterator<Item = f32>>,
knots: Option<impl Into<Vec<f32>>>, knots: Option<impl IntoIterator<Item = f32>>,
) -> Result<Self, CubicNurbsError> { ) -> Result<Self, CubicNurbsError> {
let mut control_points: Vec<P> = control_points.into(); let mut control_points: Vec<P> = control_points.into_iter().collect();
let control_points_len = control_points.len(); let control_points_len = control_points.len();
if control_points_len < 4 { if control_points_len < 4 {
@ -643,11 +643,11 @@ impl<P: VectorSpace> CubicNurbs<P> {
}); });
} }
let weights = weights let weights: Vec<f32> = weights
.map(Into::into) .map(|ws| ws.into_iter().collect())
.unwrap_or_else(|| vec![1.0; control_points_len]); .unwrap_or_else(|| vec![1.0; control_points_len]);
let mut knots: Vec<f32> = knots.map(Into::into).unwrap_or_else(|| { let mut knots: Vec<f32> = knots.map(|ks| ks.into_iter().collect()).unwrap_or_else(|| {
Self::open_uniform_knots(control_points_len) Self::open_uniform_knots(control_points_len)
.expect("The amount of control points was checked") .expect("The amount of control points was checked")
}); });
@ -846,9 +846,9 @@ pub struct LinearSpline<P: VectorSpace> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl<P: VectorSpace> LinearSpline<P> { impl<P: VectorSpace> LinearSpline<P> {
/// Create a new linear spline from a list of points to be interpolated. /// Create a new linear spline from a list of points to be interpolated.
pub fn new(points: impl Into<Vec<P>>) -> Self { pub fn new(points: impl IntoIterator<Item = P>) -> Self {
Self { Self {
points: points.into(), points: points.into_iter().collect(),
} }
} }
} }
@ -1139,8 +1139,8 @@ pub struct CubicCurve<P: VectorSpace> {
impl<P: VectorSpace> CubicCurve<P> { impl<P: VectorSpace> CubicCurve<P> {
/// Create a new curve from a collection of segments. If the collection of segments is empty, /// Create a new curve from a collection of segments. If the collection of segments is empty,
/// a curve cannot be built and `None` will be returned instead. /// a curve cannot be built and `None` will be returned instead.
pub fn from_segments(segments: impl Into<Vec<CubicSegment<P>>>) -> Option<Self> { pub fn from_segments(segments: impl IntoIterator<Item = CubicSegment<P>>) -> Option<Self> {
let segments: Vec<_> = segments.into(); let segments: Vec<_> = segments.into_iter().collect();
if segments.is_empty() { if segments.is_empty() {
None None
} else { } else {
@ -1455,8 +1455,8 @@ pub struct RationalCurve<P: VectorSpace> {
impl<P: VectorSpace> RationalCurve<P> { impl<P: VectorSpace> RationalCurve<P> {
/// Create a new curve from a collection of segments. If the collection of segments is empty, /// Create a new curve from a collection of segments. If the collection of segments is empty,
/// a curve cannot be built and `None` will be returned instead. /// a curve cannot be built and `None` will be returned instead.
pub fn from_segments(segments: impl Into<Vec<RationalSegment<P>>>) -> Option<Self> { pub fn from_segments(segments: impl IntoIterator<Item = RationalSegment<P>>) -> Option<Self> {
let segments: Vec<_> = segments.into(); let segments: Vec<_> = segments.into_iter().collect();
if segments.is_empty() { if segments.is_empty() {
None None
} else { } else {